Php __get和__set魔术方法 - 为什么我们需要这些?

时间:2011-04-25 16:15:11

标签: php zend-framework magic-methods

在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。我在快速指南上看过这个,我不明白为什么我们需要这个。

任何人都可以帮助我吗?

非常感谢

5 个答案:

答案 0 :(得分:10)

您(通常)不会直接致电__set__get。如果$foo->bar不可见且$foo->__get('bar')存在,bar会自动致电__get

在您链接到的教程中,getter和setter设置为自动调用相应的单个get / set函数。因此$foo->comment = 'bar'会间接致电$foo->setComment('bar')。这不是必要的......这只是一种便利。

在其他情况下,__get可用于创建看似只读变量的内容。

答案 1 :(得分:9)

如果你“自己制作”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。对我而言,它组织得更清晰,对象的“简单”属性与具有更大复杂性或一对多关系的属性之间存在明显的区别。

答案 2 :(得分:1)

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

  1. 这样您就不必花时间为所有属性创建vanilla访问器方法。

  2. 允许您实现属性重载。

  3. 如果你有需要特殊处理的属性,那么神奇的方法不适合你。但是,如果您的属性只包含数据并且没有依赖关系,则没有理由不使用魔术方法。

答案 3 :(得分:1)

此外,在本教程中,您可以修改__get()__set()方法,以便了解它们为什么存在。

像这样的魔法处理可以让你做一些简洁的事情,比如甚至制作“只读”属性,并且可以防止你因为混乱的getter / setter而使你的课程膨胀。

答案 4 :(得分:0)

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

通过调用setter中的特定__set可以避免此问题(感谢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;
      }
   }
}