我们应该直接访问受保护的属性还是在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
对象。他们彼此之间没有任何关系。
回到你最初的问题:如果你知道属性表示什么状态,何时/如何修改它,以及类期望此属性状态遵守什么规则,你可以直接触摸该属性。但是,如果您对类的内部工作原理了解不多,只想与其公共接口交互以获取其结果,请使用访问器方法。