不推荐使用
__get()
和
__set()
这样的魔术方法,首先这段代码并没有清晰地传达其意图。其次,客户端必须知道可用的字段才能使用魔术方法。这违反了洛米特法则(Law of Demeter),该法则指出模块不应该知道其操作对象的内部细节。
访问器、修改器和谓词应该以它们的值命名,并加上
get
、
set
和
is
前缀。
例如:
MyClass
{
private $myField;
protected function getMyField()
{
$this->myField;
}
protected function setMyField($myField)
{
$this->myField = $myField;
}
}
尽量避免创建公共 mutator(变异器),因为外部函数会诱使将其用作过程式程序使用数据结构的方式来操纵对象的内部状态,这被称为
特性嫉妒。
类的方法只应关注所属类的字段和方法,而不是其他类的字段和方法。当一个方法使用另一个对象的访问器和 mutator 来操纵该对象内部的数据时,它就会
嫉妒 该对象的范围。因此,我们想要消除特性嫉妒,因为它会向另一个类公开该类的内部机制。然而,特性嫉妒有时是必要的,例如,在一个对象的方法需要另一个对象的数据来进行操作的情况下,将该对象的方法移动到持有数据的对象中会违反面向对象设计原则。
那么如果其他类不应该使用访问器和 mutator,为什么我们还要拥有它们呢?嗯,将访问器和 mutator 设置为受保护的,允许派生类访问父类的私有字段,但仍然可以防止外部偷窥和操纵对象的内部状态。
但是,我们不能将字段设置为受保护吗?这样做确实可行,但你就无法屏蔽子类设置字段的可能性。
在 PHP 中,我们甚至可以认为让一个类使用私有 mutator 是有意义的,这样我们就有机会在将值设置到字段之前进行类型检查。
例如:
MyClass
{
private $myField;
protected function getMyField()
{
$this->myField;
}
private function setMyField($myField)
{
if (!(is_int($myField) || null === $myField)) {
throw new \InvalidArgumentException(sprintf(
'%s expects $myField to be integer; received %s.'
__METHOD__,
gettype($myField)
));
}
$this->myField = $myField;
}
}
如果$myField
不是整数或null
,则会抛出异常。然而,也可以认为这样的代码表明对自己的编码存在不信任。无论如何,私有mutator可以轻松更改为protected,以允许子类操纵该字段,并且可以将访问器方法设置为private或删除以防止子类读取该字段。
$foo
(所有成员都应该是私有的,对吧?),并且您想要一个访问器来访问成员$foo
,但只希望该类能够访问它。因此,您需要一个private function get_foo()
,这是一个私有属性。 - StackOverflowNewbie$this->property
。Getter和setter是用来在变量的值从类外设置时获取其值的。如果你真的需要一个私有函数,为什么要使用魔术函数?你可以给它取一个别的名字。 - Shameer