我什么时候应该在PHP中使用uuu construct()、uu get()、uuu set()和uuu call()?

我什么时候应该在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

A,但我把它留在了我的标题中,供搜索者使用

显然,uuu get和uu set接受一个参数,该参数就是要获取或设置的变量。但是,您必须知道变量名(例如,知道人的年龄是$age而不是$myAge)。因此,如果您必须知道变量名,我不认为这有什么意义,特别是如果您使用的是您不熟悉的代码(例如库)

我找到了一些解释和的页面,但我仍然不知道它们为什么或什么时候有用。

可能会有用。(请注意,您所说的是不正确的-
\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”方法。在访问不存在的属性时调用,在尝试写入不存在的属性时调用,在调用不存在的方法时调用

例如,假设有一个类管理您的配置:

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;
    }
}