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

当前回答

谷歌已经发布了一个关于PHP优化的指南,结论是:

没有getter和setter优化PHP

不,你不能使用魔法方法。对于PHP来说,魔法方法是邪恶的。为什么?

它们很难调试。 会对性能产生负面影响。 它们需要编写更多的代码。

PHP不是Java、c++或c#。PHP是不同的,它遵循不同的规则。

其他回答

如果你喜欢使用__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;
    }
}

验证+格式化/导出值

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);
    }
}

一般来说,第一种方法总体上更受欢迎,因为具有编程知识的人可以轻松地转换到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……用他们该用的方式去使用他们。

为什么使用getter和setter ?

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