Php 我们应该直接访问受保护的属性还是使用getter?

Php 我们应该直接访问受保护的属性还是使用getter?,php,Php,我们应该直接访问受保护的属性还是使用PHP中的getter 我有两个班,一个是另一个的女儿。在mother中,我声明某些属性为protected,并为我的属性生成所有getter。因此,我可以直接或通过getter访问和定义这些属性,但我不知道是否有更好的解决方案 例如: class Mother { private $privateProperty; protected $protectedProperty; public $publicProperty;

我们应该直接访问受保护的属性还是使用PHP中的getter

我有两个班,一个是另一个的女儿。在mother中,我声明某些属性为protected,并为我的属性生成所有getter。因此,我可以直接或通过getter访问和定义这些属性,但我不知道是否有更好的解决方案

例如:

class Mother {

    private $privateProperty;
    protected $protectedProperty;
    public $publicProperty;

    /*** Private property accessors ***/   

    public function setPrivateProperty($value)
    {
        $this->privateProperty = $value;
    }

    public function getPrivateProperty()
    {
        return $this->privateProperty;
    }

    /*** Protected property accessors ***/   

    public function setProtectedProperty($value)
    {
        $this->protectedProperty = $value;
    }

    public function getProtectedProperty()
    {
        return $this->protectedProperty;
    }
}

class Child extends Mother {

    public function showProtectedProperty() {
        return $this->getProtectedProperty();   // This way ?
        return $this->protectedProperty;        // Or this way ?
    }

    public function defineProtectedProperty() {
        $this->setProtectedProperty('value');   // This way ?
        $this->protectedProperty = 'value';     // Or this way ?
    }
}

在这个例子中,我知道我不能直接访问/设置私有属性,它对公共属性没有用处。但对于受保护的财产,我可以使用两种方法。那么,有什么标准可以使用吗?

当您确实在类层次结构中使用getter和setter时,最好的封装就完成了。这意味着:属性应该是私有的,并且getter/setter受到保护(如果不是公共的话)

例如,如果您想要记录对某些属性的访问,想要添加一个筛选方法或另一个检查,那么如果您只是在派生类中访问这些属性,那么整个机制将被删除


(当然,在某些情况下,您只需将属性公开以缩短代码,因为您知道该类实际上只是一个数据持有者……但是,在这种情况下,这些属性仍然不会受到保护,而只是公开的)

我不久前回答了一个类似的问题:

我不会说哪个更好或者更坏,因为这部分取决于你的情况(在我看来)。但是,考虑到你的吸收器和设定器可能在稍后改变实现,而绕过它们会跳过这个逻辑。 例如,如果稍后向某些setter字段添加“dirty”标志,会发生什么情况?通过在内部代码中调用setter,可以在不更改任何其他代码的情况下设置脏标志。在许多情况下,这将是一件好事


您可能需要特殊的规则,比如初始化代码应该跳过使用setter。最重要的是在项目中选择一个合适的策略,并坚持它以保持一致性。

您甚至不应该认为属性具有“getter/setter”。这两件事是不同的。属性存储状态,getter返回值,setter修改对象状态。有时,它们可能有非常直接的1:1相关性,但它们不需要

事实上,如果setter所做的只是
$this->foo=$foo
,而getter确实
返回$this->foo
首先将其设置为
公共
属性
无论出于何种目的,它都已经存在。让函数修饰这个属性是没有意义的,它们实际上不会增加任何价值

为了便于讨论,请想象这样一节课:

class Foo {

    protected $timestamp;

    public function setStartTime($int) {
        $this->timestamp = new DateTime("@$int");
    }

    public function getElapsedTime() {
        return $this->timestamp->diff(new DateTime);
    }

}
这更清楚地说明了状态、状态修改和值返回之间的分离。“setter”接受一个整数,属性存储一个
DateTime
对象,“getter”返回一个
DateInterval
对象。他们之间真的没有任何关系


回到最初的问题:如果您知道属性表示什么状态,何时/如何修改它,以及类希望该属性状态遵守什么规则,那么您可以直接接触属性。但是,如果您对类的内部工作不太了解,只想与它的公共接口交互以获得结果,请使用访问器方法。

在上面的代码中,您最好创建公共属性……我不明白,您作为示例展示的两个函数实际上不是访问器。这些是基于属性计算某物的函数。在您的示例中,如果您想从另一个类访问$timestamp属性,您将如何做?这正是我试图说明的要点。不要认为属性具有某些完全等价和可互换的方法。如果你有一个可互换的存取器,你可能一开始就不需要它。如果访问器执行了某些操作,那么您是要直接访问属性还是要获取访问器的结果,答案应该是不言而喻的。我的例子非常极端,但这是故意的。试着像这个例子一样查看所有属性访问器关系。我理解你的观点,但是:*如果我们不使用访问器,为什么要使用神奇的方法?*而且,我使用的是Doctrine/Symfony2,所有实体都具有访问器的私有属性:,为什么要使用此解决方案?@john Magic methods主要允许您设计一个看起来与实际实现不同的API。SimpleXML是一个很好地使用magic方法的例子。它看起来像一个普通的对象,但每当你访问任何“属性”时,很多魔法都会在幕后发生。我认为你不应该对日常对象太依赖魔法方法。@john第二,拥有“愚蠢的1:1访问器”的好处是,它为你提供了一个选项,可以在以后的属性访问中扩展任何正在发生的事情。如果你告诉所有用户直接使用
$foo->bar
,但后来你决定实际上需要运行一些代码,并希望所有人都使用
$foo->getBar()
,那么你就完蛋了。我允许这是从一开始就使用访问器的一个原因。然而,再一次,从一开始就像上面所描述的那样思考。你只需要进入那个空间。然后OP的问题就自行解决了。