我不是PHP开发人员,所以我想知道在PHP中使用显式getter/setter的优点和缺点是什么,在纯OOP风格中,带有私有字段(我喜欢的方式):

class MyClass {
    private $firstField;
    private $secondField;

    public function getFirstField() {
        return $this->firstField;
    }
    public function setFirstField($x) {
        $this->firstField = $x;
    }
    public function getSecondField() {
        return $this->secondField;
    }
    public function setSecondField($x) {
        $this->secondField = $x;
    }
}

或者只是公共字段:

class MyClass {
    public $firstField;
    public $secondField;
}

当前回答

为什么使用getter和setter ?

可伸缩性:重构getter比在项目代码中搜索所有的var赋值更容易。 调试:可以在setter和getter中设置断点。 更简洁:神奇的函数不是很好的解决方案,你的IDE不会建议代码。最好使用模板来快速编写getter。

其他回答

一般来说,第一种方法总体上更受欢迎,因为具有编程知识的人可以轻松地转换到PHP,并以面向对象的方式完成工作。第一种方法更为普遍。我的建议是坚持使用在许多语言中都行之有效的方法。然后,当你使用另一种语言时,你将准备好完成一些事情(而不是花时间重新发明轮子)。

更新:不要使用这个答案,因为这是我在学习过程中发现的非常愚蠢的代码。使用普通的getter和setter会更好。


我通常使用变量名作为函数名,并添加可选参数到该函数,这样当可选参数由调用者填充时,然后将其设置为属性并返回$this对象(链),然后当可选参数没有由调用者指定时,我只是将属性返回给调用者。

我的例子:

class Model
{
     private $propOne;
     private $propTwo;

     public function propOne($propVal = '')
     {
          if ($propVal === '') {
              return $this->propOne;
          } else {
              $this->propOne = $propVal;
              return $this;
          }
     }

     public function propTwo($propVal = '')
     {
          if ($propVal === '') {
              return $this->propTwo;
          } else {
              $this->propTwo = $propVal;
              return $this;
          }
     }
}

Well, PHP does have magic methods __get, __set, __isset & __unset, which is always a start. Alas proper (get it?) OO properties is more than magic methods. The main problem with PHP's implementation is that magic methods are called for all inaccessible properties. Which means you have to Repeat Yourself (eg. by calling property_exists()) in the magic methods when determining if name is actually a property of your object. And you can't really solve this general problem with a base class unless all your classes inherit from ie. ClassWithProperties, since PHP lacks multiple inheritance.

相比之下,Python的新样式类提供了property(),它允许显式地定义所有属性。c#有特殊的语法。

http://en.wikipedia.org/wiki/Property_(编程)

There are many ways to create sourcecode in a netbeans-convention. This is nice. It makes thinks such easyer === FALSE. Just use the traditionel, specially if you are not sure which one of the properties should be encapsuled and which one not. I know, it is a boi.... pla... code, but for debugging-works and many other thinks it is the better, clear way. Dont spend to much time with thousend of arts how to make simple getters and setters. You cannot implement too some design patterns like the demeter-rule and so on, if you use magics. In specific situation you can use magic_calls or for small, fast and clear solutions. Sure you could make solutions for design-patters in this way too, but why to make you live more difficult.

验证+格式化/导出值

setter允许您验证数据,getter允许您格式化或派生数据。对象允许您将数据及其验证和格式化代码封装到一个鼓励DRY的整洁包中。

例如,考虑以下包含出生日期的简单类。

class BirthDate {

    private $birth_date;

    public function getBirthDate($format='Y-m-d') {
        //format $birth_date ...
        //$birth_date = ...
        return $birth_date;
    }

    public function setBirthDate($birth_date) {                   
        //if($birth_date is not valid) throw an exception ...          
        $this->birth_date = $birth_date;
    }

    public function getAge() {
        //calculate age ...
        return $age;
    }

    public function getDaysUntilBirthday() {
        //calculate days until birth days
        return $days;
    }
}

您需要验证所设置的值是否为

有效日期 不是将来

而且您不希望在整个应用程序中(或在多个应用程序中)执行此验证。相反,将成员变量设置为受保护或私有(以便使setter成为唯一的访问点)并在setter中进行验证更容易,因为这样无论对象来自应用程序的哪个部分,您都知道对象包含有效的出生日期,如果您想添加更多验证,那么可以将其添加到单个位置。

你可能想要添加多个格式化程序来操作同一个成员变量,即getAge()和getDaysUntilBirthday(),你可能想要在getBirthDate()中强制一个可配置的格式,这取决于地区。因此,我更喜欢通过getter始终访问值,而不是将$date->getAge()与$date->birth_date混合。

在扩展对象时,getter和setter也很有用。例如,假设您的应用程序需要在某些地方允许150年以上的出生日期,而在其他地方则不允许。在不重复任何代码的情况下解决这个问题的一种方法是扩展BirthDate对象,并将额外的验证放在setter中。

class LivingBirthDate extends BirthDate {

    public function setBirthDate($birth_date) {
        //if $birth_date is greater than 150 years throw an exception
        //else pass to parent's setter
        return parent::setBirthDate($birth_date);
    }
}