这将是我的设计过程中一个受欢迎的变化,因为我看到对getter/setters的需求消失了,但是这样做还可能出现哪些其他障碍/好处呢?
您将失去在特定属性上实现特殊 get/set 逻辑的能力。对于标量属性(字符串,整数,布尔值),也许这没有问题。但是,如果您有一个作为延迟加载的类实例的属性,该怎么办?
class Document
{
protected $_createdBy;
public function getCreatedBy()
{
if (is_integer($this->_createdBy)) {
$this->_createdBy = UserFactory::loadUserById($this->_createdBy);
}
return $this->_createdBy;
}
}
该技巧仅适用于方法。你可以使用 和 用于此逻辑,但是当您添加属性时,最终会得到一个大的令人讨厌的块:__get
__set
switch()
public function __get($name)
{
switch ($name) {
case 'createdBy':
// blah blah blah
case 'createdDate':
// more stuff
// more case statements until you scream
}
}
如果只想避免或推迟编写 getter 和 setter,请使用 magic 方法来捕获遵循 和 命名约定的方法调用。您可以将所有默认的 get/set 逻辑放入,并且再也不碰它:__call
getProperty()
setProperty()
__call
abstract class Object
{
public function __call($method, $args)
{
$key = '_' . strtolower(substr($method, 3, 1)) . substr($method, 4);
$value = isset($args[0]) ? $args[0] : null;
switch (substr($method, 0, 3)) {
case 'get':
if (property_exists($this, $key)) {
return $this->$key;
}
break;
case 'set':
if (property_exists($this, $key)) {
$this->$key = $value;
return $this;
}
break;
case 'has':
return property_exists($this, $key);
break;
}
throw new Exception('Method "' . $method . '" does not exist and was not trapped in __call()');
}
}
从开发的角度来看,这种方法非常快,因为您只需扩展 Object 类,定义一些属性,就可以开始比赛了:
class Foo extends Object
{
protected $_bar = 12345;
}
$foo = new Foo();
echo $foo->getBar(); // outputs '12345'
$foo->setBar(67890); // next call to getBar() returns 67890
$foo->getBaz(); // oops! 'baz' doesn't exist, exception for you
从执行的角度来看,它很慢,因为魔术方法非常慢,但是您以后可以通过定义显式和方法来缓解这种情况(因为只有在调用未定义的方法时才调用)。但是,如果某个特定的属性不经常被访问,也许你不在乎它有多慢。关键是,以后很容易添加特殊的 get/set 方法,而代码的其余部分永远不会知道其中的区别。getBar()
setBar()
__call
我从Magento那里抄写了这种方法,我发现它对开发人员非常友好。在为不存在的属性调用 get/set 时引发异常有助于避免由拼写错误引起的幻像错误。将特定于属性的逻辑保存在其自己的 get/set 方法中,使代码更易于维护。但是,您不必在开始时编写所有访问器方法,您可以轻松返回并添加它们,而无需重构所有其他代码。
问题是,您要优化什么?开发人员时间还是代码速度?如果要优化代码速度,请确保在围绕瓶颈构建代码之前知道瓶颈的位置。过早优化是万恶之源。