我不是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;
}

当前回答

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

准备好了!

其他回答

更新:不要使用这个答案,因为这是我在学习过程中发现的非常愚蠢的代码。使用普通的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;
          }
     }
}

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.

如果你喜欢使用__call函数,你可以使用这个方法。它适用于

GET => $this->属性() SET => $this->属性($value) getProperty() => $this-> SET => $this->setProperty($value)

kalsdas

public function __call($name, $arguments) {

    //Getting and setting with $this->property($optional);

    if (property_exists(get_class($this), $name)) {


        //Always set the value if a parameter is passed
        if (count($arguments) == 1) {
            /* set */
            $this->$name = $arguments[0];
        } else if (count($arguments) > 1) {
            throw new \Exception("Setter for $name only accepts one parameter.");
        }

        //Always return the value (Even on the set)
        return $this->$name;
    }

    //If it doesn't chech if its a normal old type setter ot getter
    //Getting and setting with $this->getProperty($optional);
    //Getting and setting with $this->setProperty($optional);
    $prefix = substr($name, 0, 3);
    $property = strtolower($name[3]) . substr($name, 4);
    switch ($prefix) {
        case 'get':
            return $this->$property;
            break;
        case 'set':
            //Always set the value if a parameter is passed
            if (count($arguments) != 1) {
                throw new \Exception("Setter for $name requires exactly one parameter.");
            }
            $this->$property = $arguments[0];
            //Always return the value (Even on the set)
            return $this->$name;
        default:
            throw new \Exception("Property $name doesn't exist.");
            break;
    }
}

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_(编程)

为什么使用getter和setter ?

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