源于这个关于使用__get()
和__set()
访问私有变量的问题,我想了解它们的一般使用方式。我想知道何时何地是使用重载函数的最佳时间,以及你在哪里使用过重载函数(如果你有的话)。
为了清楚起见,我们正在谈论这些功能:http ://us2.php.net/manual/en/language.oop5.magic.php
源于这个关于使用__get()
和__set()
访问私有变量的问题,我想了解它们的一般使用方式。我想知道何时何地是使用重载函数的最佳时间,以及你在哪里使用过重载函数(如果你有的话)。
为了清楚起见,我们正在谈论这些功能:http ://us2.php.net/manual/en/language.oop5.magic.php
我不记得在我的应用程序中经常使用 PHP 的魔法方法,但我记得有一种情况__get()
非常有用。
以前我在 CakePHP 框架中开发一个应用程序,它有很多模型,并且在特定控制器中使用的所有模型都被初始化,即使方法只使用其中的一两个(这就是 Cake 的工作方式)。所以我决定将其更改为惰性模型到惰性(第一次使用模型时加载模型)。
我所做的只是添加了一个非常简单的__get()
函数来查找具有特定名称的模型并加载它。这就像 3-4 行代码。我在 AppController 中定义了这一点(所有 CakePHP 类都派生自该控制器),突然我的应用程序获得了速度并使用了更少的内存。
后来我更进一步,并以同样的方式加载了惰性组件。
另一个同样来自 CakePHP 的好例子是 Cake 如何搜索模型。基本上,您有两种方法:find()
和findAll()
在每个模型中,但您也可以使用方法findBy<FieldName>()
和findAllBy<FieldName>()
.
例如,如果您有 db 表
notes(id, date, title, body)
并为此创建蛋糕模型。可以使用findById()
,等方法findByTitle()
。您只需要 CamelCase 数据库字段,您可以更快地搜索任何字段。
蛋糕通过使用__call()
魔术方法来做到这一点。如果您尝试执行不存在的方法,然后它只是运行find()
或findAll()
使用从方法名称和参数动态创建的条件,则会调用此方法。这实现起来非常简单,并且可以给您带来很多好处。
我使用 __get() 和 __set() 来访问私有数组的元素,即:
class Something {
private $data;
public function __set($key, $value) {
//put validation here
$this->data[$key] = $value;
}
public function __get($key) {
if (!array_key_exists($this->data, $key)) {
throw new Exception("Invalid member $key.");
} else {
return $this->data[$key];
}
}
}
因此,通过一些验证,像 $person->age = "asdf" 这样的东西会立即抛出异常(而如果 age 是公共成员就可以了。)
同样在 __set() 中,如果您不希望班级中有任意“成员”,您可以限制哪些键有效。
一些样本:
class formatedContainer {
private $holder;
protected $mode = "formated";
public function __set($var, $value) {
$formated = chunk_split($value, 4, "-");
if(substr($formated, -1) == "-")
$formated = substr($formated, 0, strlen($formated) - 1);
$this->holder[$var] = array('formated' => $formated, 'plain' => $value);
}
public function __get($var) {
return $this->holder[$var][$this->mode];
}
public function getPlain() {
$this->mode = "plain";
}
public function getFormated() {
$this->mode = "formated";
}
}
$texts = new formatedContainer();
$texts->myText = md5(uniqid());
$texts->anotherText = md5("I don't change!");
//Prints something like: 440e-6816-b2f5-7aa5-9627-9cc8-26ef-ef3b
echo $texts->myText;
$texts->getPlain();
//Prints something like: 8559d37c5a02714dca8bd1ec50a4603a
echo "<br/>" . $texts->anotherText;
有点没用,但我想你可以得到一个想法。:}
网上有很多例子,使用__get()
和__set()
结合私有“属性数组”。我希望在我的类定义中实现有趣的转折,即能够实际声明公共属性并仍然使用这些神奇的拦截器——用于更多的自我记录代码并让我的 IDE 能够完成代码完成等。通常,如果这些属性已声明,__get()
不会__set()
被调用。我发现如果我unset()
在类构造函数中使用相同的属性,我可以两全其美。