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


Should we access protected properties directly or with getters?

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

我有两个班级,一个是另一个的女儿。在母亲中,我声明某些属性受保护,并为我的属性生成所有 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 受到保护(如果不是公共的(。

例如,如果要记录对某些属性的访问,想要添加筛选方法或其他检查,则在派生类中访问这些属性时,将删除整个机制。

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

不久

前我在 Programmers.SE 上回答了一个类似的问题:

我不会说哪个更好或更坏,因为这部分取决于您的情况(在我看来(。但考虑到你的 getter 和 setter 可能会在以后更改实现,绕过它们会跳过该逻辑。

例如,如果您稍后向某些 setter 字段添加"脏"标志会发生什么情况?通过在内部代码中调用 setter,您将在不更改任何其他代码的情况下设置脏标志。在许多情况下,这将是一件好事。

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

你甚至不应该认为属性具有"getter/setter"。这两者是不同的东西。属性存储状态,getter 返回值,资源库修改对象状态。有时这些可能具有非常直接的 1:1 相关性,但它们不需要。

事实上,如果你的二传手所做的只是$this->foo = $foo而吸气手所做的return $this->foo,那么首先让它成为一个public属性!出于所有意图和目的,它已经是。让函数修饰此属性是没有意义的,它们实际上不会增加任何价值。

为了讨论起见,想象一下这样的类:

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对象。他们彼此之间没有任何关系。

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