Php的__get和__set魔法方法——为什么我们在这里需要它们?


zend framework - Php __get and __set magic methods - why do we need those here?

在Zend快速入门指南这里http://framework.zend.com/manual/en/learning.quickstart.create-model.html我们可以看到:

class Application_Model_Guestbook
{
    protected $_comment;
    protected $_created;
    protected $_email;
    protected $_id;
    public function __set($name, $value);
    public function __get($name);

    public function setComment($text);
    public function getComment();
...

我通常创建getter和setter而不使用任何魔法方法。我在快速指南上看到了这个,我不明白为什么我们需要这个。

有谁能帮我吗?

Thanks to lot

您(通常)从不直接调用__set__get。如果bar不可见且__get存在,$foo->bar将自动调用$foo->__get('bar')

在你所链接到的教程中,getter和setter被设置为自动调用适当的单个get/set函数。所以$foo->comment = 'bar'会间接调用$foo->setComment('bar')。这没有必要……这只是为了方便。

在其他情况下,__get可以用来创建一个只读变量。

如果您"自制" getter和setter,您将为每个属性制作两个函数:getPropname()setPropname。通过使用PHP的"魔法方法"setter/getter,您不必为每个属性编写单独的方法。您可以设置/获取属性,就好像它们是公共的一样。在重载函数中,添加特定于每个属性的逻辑。例子:

public function __set($name, $value) {
 switch ($name) {
   case 'comments':
     // do stuff to set comments
     break;
   case 'parent_user':
     // do stuff to set parent user
     break;
 }
}
public function __get($name) {
 switch ($name) {
   case 'comments':
     // do stuff to get comments
     break;
   case 'parent_user':
     // do stuff to get parent user
     break;
 }
}

现在我可以通过使用$obj->comments来设置或获取注释

要在不使用重载的情况下实现上述功能,我必须编写4个不同的方法。这实际上更多的是关于代码组织,无论是在实际文件方面,还是在为项目中的对象创建标准化接口方面。

我个人更喜欢像你那样做,为我需要复杂的getter/setter的每个属性编写单独的方法。对我来说,它的组织更清晰,对象的"简单"属性和那些更复杂或一对多关系的属性之间有明确的分离。

__get__set魔术方法存在两个原因:

  1. 这样你就不必花时间为你所有的属性创建普通的访问方法。

  2. 允许你实现属性重载

如果您有需要特殊处理的属性,那么魔法方法不适合您。然而,如果你的属性只是包含数据,没有依赖关系,那么没有理由不使用魔法方法。

在本教程中,您将进一步修改__get()__set()方法,以便您了解它们存在的原因。

拥有这样的神奇处理可以让你做一些整洁的事情,甚至可以创建"只读"属性,并且可以防止你用杂乱的getter/setter加载来膨胀你的类。

当您使用__set并希望在子类中覆盖setter功能时,您将遇到问题。您必须复制__set中的整个代码并仅更改特定部分,而不是简单地覆盖一个特定的setter函数->冗余代码

这个问题可以通过在__set中调用特定的setter来避免(感谢cHao提供的提示)。

的例子:

class Foo1 {
   protected $normal;
   protected $special;
   public function setSpecial($special) {
      if ($special == isReallySpecial()) {
         $this->special = $special;
      }
   }
   public function __set($key, $value) {
      switch ($key) {
         case 'normal':
            $this->normal = $value;
            break;
         case 'special':
            $this->setSpecial($value);
      }
   }
}
class Foo2 extends Foo1 {
   public function setSpecial($special) {
      if ($special == isNotReallySpecial()) {
         $this->special = $special;
      }
   }
}