我不是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。

其他回答

class MyClass {
    private $firstField;
    private $secondField;
    private $thirdField;

    public function __get( $name ) {
        if( method_exists( $this , $method = ( 'get' . ucfirst( $name  ) ) ) )
            return $this->$method();
        else
            throw new Exception( 'Can\'t get property ' . $name );
    }

    public function __set( $name , $value ) {
        if( method_exists( $this , $method = ( 'set' . ucfirst( $name  ) ) ) )
            return $this->$method( $value );
        else
            throw new Exception( 'Can\'t set property ' . $name );
    }

    public function __isset( $name )
    {
        return method_exists( $this , 'get' . ucfirst( $name  ) ) 
            || method_exists( $this , 'set' . ucfirst( $name  ) );
    }

    public function getFirstField() {
        return $this->firstField;
    }

    protected function setFirstField($x) {
        $this->firstField = $x;
    }

    private function getSecondField() {
        return $this->secondField;
    }
}

$obj = new MyClass();

echo $obj->firstField; // works
$obj->firstField = 'value'; // works

echo $obj->getFirstField(); // works
$obj->setFirstField( 'value' ); // not works, method is protected

echo $obj->secondField; // works
echo $obj->getSecondField(); // not works, method is private

$obj->secondField = 'value'; // not works, setter not exists

echo $obj->thirdField; // not works, property not exists

isset( $obj->firstField ); // returns true
isset( $obj->secondField ); // returns true
isset( $obj->thirdField ); // returns false

准备好了!

封装在任何面向对象语言中都很重要,与受欢迎程度无关。在动态类型语言(如PHP)中,它特别有用,因为如果不使用设置符,几乎没有办法确保属性是特定类型的。

在PHP中,这是有效的:

class Foo {
   public $bar; // should be an integer
}
$foo = new Foo;
$foo->bar = "string";

在Java中,它没有:

class Foo {
   public int bar;
}
Foo myFoo = new Foo();
myFoo.bar = "string"; // error

使用魔法方法(__get和__set)也可以,但只有当访问的属性的可见性低于当前作用域可以访问的时候。如果使用不当,调试时很容易让您头疼。

你可以使用php神奇的方法__get和__set。

<?php
class MyClass {
  private $firstField;
  private $secondField;

  public function __get($property) {
    if (property_exists($this, $property)) {
      return $this->$property;
    }
  }

  public function __set($property, $value) {
    if (property_exists($this, $property)) {
      $this->$property = $value;
    }

    return $this;
  }
}
?>

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

在阅读了其他建议后,我倾向于这样说:

作为GENERIC规则,你不会总是为所有属性定义setter,特别是“内部”属性(信号量、内部标志……)。只读属性显然没有setter,所以有些属性只有getter;这就是__get()缩小代码的地方:

define a __get() (magical global getters) for all those properties which are alike, group them in arrays so: they'll share common characteristics: monetary values will/may come up properly formatted, dates in an specific layout (ISO, US, Intl.), etc. the code itself can verify that only existing & allowed properties are being read using this magical method. whenever you need to create a new similar property, just declare it and add its name to the proper array and it's done. That's way FASTER than defining a new getter, perhaps with some lines of code REPEATED again and again all over the class code.

是的!我们也可以写一个私有方法来做到这一点,但话又说回来,我们将声明许多方法(++内存),最终调用另一个总是相同的方法。为什么不写一个单一的方法来管理它们呢?(是的!双关语!)):

Magic setter也可以只响应特定的属性,因此可以单独在一个方法中筛选所有日期类型属性的无效值。如果日期类型属性列在数组中,则可以轻松定义它们的setter。当然,这只是一个例子。有太多的情况。

About readability... Well... That's another debate: I don't like to be bound to the uses of an IDE (in fact, I don't use them, they tend to tell me (and force me) how to write... and I have my likes about coding "beauty"). I tend to be consistent about naming, so using ctags and a couple of other aids is sufficient to me... Anyway: once all this magic setters and getters are done, I write the other setters that are too specific or "special" to be generalized in a __set() method. And that covers all I need about getting and setting properties. Of course: there's not always a common ground, or there are such a few properties that is not worth the trouble of coding a magical method, and then there's still the old good traditional setter/getter pair.

编程语言就是人类的人工语言。因此,它们都有自己的语调或重音、语法和风格,所以我不会假装用与Java或c#相同的“重音”来编写Ruby或Python代码,也不会编写类似Perl或SQL的JavaScript或PHP……用他们该用的方式去使用他们。