我什么时候应该在PHP中使用uuu construct()、uu get()、uuu set()和uuu call()?
A,但我把它留在了我的标题中,供搜索者使用 显然,uuu get和uu set接受一个参数,该参数就是要获取或设置的变量。但是,您必须知道变量名(例如,知道人的年龄是$age而不是$myAge)。因此,如果您必须知道变量名,我不认为这有什么意义,特别是如果您使用的是您不熟悉的代码(例如库) 我找到了一些解释和的页面,但我仍然不知道它们为什么或什么时候有用。可能会有用。(请注意,您所说的是不正确的-我什么时候应该在PHP中使用uuu construct()、uu get()、uuu set()和uuu call()?,php,magic-function,Php,Magic Function,A,但我把它留在了我的标题中,供搜索者使用 显然,uuu get和uu set接受一个参数,该参数就是要获取或设置的变量。但是,您必须知道变量名(例如,知道人的年龄是$age而不是$myAge)。因此,如果您必须知道变量名,我不认为这有什么意义,特别是如果您使用的是您不熟悉的代码(例如库) 我找到了一些解释和的页面,但我仍然不知道它们为什么或什么时候有用。可能会有用。(请注意,您所说的是不正确的-\uuuu set()将变量名称和值作为参数。\uuuu get()仅将变量名称作为参数) \uuu
\uuuu set()
将变量名称和值作为参数。\uuuu get()
仅将变量名称作为参数)
\uuuu get()
和\uuuu set()
在希望提供对变量的通用访问的库函数中非常有用。例如,在ActiveRecord类中,您可能希望人们能够作为对象属性访问数据库字段。例如,在Kohana PHP框架中,您可以使用:
$user = ORM::factory('user', 1);
$email = $user->email_address;
这是通过使用\uu get()
和\uu set()
实现的
当使用\u call()
时,可以实现类似的功能,也就是说,您可以检测何时有人在调用getProperty()和setProperty(),并进行相应的处理。它们用于做“聪明”的事情
例如,您可以使用\uu set()
和\uu get()
与数据库对话。您的代码将是:$myObject->foo=“bar”这可能会在幕后更新数据库记录。当然,您必须非常小心,否则您的性能可能会受到影响,因此在使用包含易于访问的数据的PHP对象时,围绕“聪明”的引号是非常有用的:方法。在访问不存在的属性时调用,在尝试写入不存在的属性时调用,在调用不存在的方法时调用
例如,假设有一个类管理您的配置:
class Config
{
protected $_data = array();
public function __set($key, $val)
{
$this->_data[$key] = $val;
}
public function __get($key)
{
return $this->_data[$key];
}
...etc
}
这使得读取和写入对象变得更加容易,并允许您在读取或写入对象时使用自定义功能。
例如:
__get()、_set()和_call()是PHP称之为“神奇方法”的名称,我认为这有点愚蠢-我认为“hook”更合适。无论如何,我离题了
其目的是为访问对象上未定义的数据成员(属性或方法)时提供执行情况,这可用于各种“聪明”的想法,如变量隐藏、消息转发等
然而,这是有代价的——调用这些数据的调用要比调用已定义的数据成员慢10倍左右。重新定义\uuu get
和\uu set
在核心类中尤其有用。例如,如果您不希望配置被意外覆盖,但仍希望从中获取数据:
class Example
{
private $config = array('password' => 'pAsSwOrD');
public function __get($name)
{
return $this->config[$name];
}
}
使用它们的一个很好的理由是注册表系统(我认为Zend Framework将其实现为注册表或配置类iirc),因此您可以执行以下操作
$conf = new Config();
$conf->parent->child->grandchild = 'foo';
这些属性中的每一个都是自动生成的配置对象,类似于:
function __get($key) {
return new Config($key);
}
显然,如果$conf->parent已经存在,就不会调用_get()方法,因此使用它来生成新变量是一个很好的技巧
请记住,我刚才引用的代码不是功能性的,我只是为了举例而快速编写了它。可能不是世界上最干净的设计,但我有一个情况,我有很多代码引用了类中的实例变量,即:
$obj->value = 'blah';
echo $obj->value;
但后来,我想在某些情况下设置“value”时做一些特殊的事情,所以我重命名了value变量,并使用所需的更改实现了_set()和_get()
其余的代码不知道有什么区别。另一个有用的魔法方法应用,特别是\uuuu get
和\uu set
和\uu toString
是模板。只需编写使用神奇方法的简单适配器,就可以使代码独立于模板引擎。如果您想移动到另一个模板引擎,只需更改这些方法即可
class View {
public $templateFile;
protected $properties = array();
public function __set($property, $value) {
$this->properties[$property] = $value;
}
public function __get($property) {
return @$this->properties[$property];
}
public function __toString() {
require_once 'smarty/libs/Smarty.class.php';
$smarty = new Smarty();
$smarty->template_dir = 'view';
$smarty->compile_dir = 'smarty/compile';
$smarty->config_dir = 'smarty/config';
$smarty->cache_dir = 'smarty/cache';
foreach ($this->properties as $property => $value) {
$smarty->assign($property, $value);
}
return $smarty->fetch($this->templateFile);
}
}
这种方法的潜在好处是,您可以将视图对象嵌套在另一个对象中:
$index = new View();
$index->templateFile = 'index.tpl';
$topNav = new View();
$topNav->templateFile = 'topNav.tpl';
$index->topNav = $topNav;
在index.tpl
中,嵌套如下所示:
<html>
<head></head>
<body>
{$topNav}
Welcome to Foobar Corporation.
</body>
</html>
{$topNav}
欢迎来到福巴公司。
只要echo$index,所有嵌套视图对象都会动态转换为字符串(确切地说是HTML)代码>我认为这对代码设计不利。如果您知道并做了一个好的设计,那么您就不需要在代码中使用\uu set()
和\uu get()
。阅读代码也非常重要,如果您使用studio(例如Zend studio),使用\uuu set()
和\uu get()
时,您将看不到您的类属性。PHP允许我们动态创建可能导致问题的类变量。您可以使用_set和_get方法来限制此行为。请参见下面的示例
class Person {
public $name;
public function printProperties(){
print_r(get_object_vars($this));
}
}
$person = new Person();
$person->name = 'Jay'; //This is valid
$person->printProperties();
$person->age = '26'; //This shouldn't work...but it does
$person->printProperties();
为了防止上述情况,您可以这样做
public function __set($name, $value){
$classVar = get_object_vars($this);
if(in_array($name, $classVar)){
$this->$name = $value;
}
}
希望这有帮助……我不喜欢这些方法的这种用法。它充其量只是一种语法上的糖分,只会减慢应用程序的速度。我更希望看到一个实现SPL ArrayAccess接口的类,或者只是一组通用的get/set方法。这些应该是“在必要时使用,而不是在方便时使用”。你有任何关于它速度较慢的参考资料吗?不是我不相信你(因为我相信),而是我希望你不相信。
public function __set($name, $value){
$classVar = get_object_vars($this);
if(in_array($name, $classVar)){
$this->$name = $value;
}
}