为了扩展Berry的答案,将访问级别设置为protected允许__get和__set与显式声明的属性一起使用(至少在类外部访问时),并且速度相当慢,我将引用另一个问题的评论关于此主题,并为使用它提供理由:
我同意__get到自定义get函数(做相同的事情)的速度更慢,这是__get()的时间为0.0124455,而这0.0024445是10000次循环后用于自定义get()的时间。– Melsi 2012年11月23日,22 : 32最佳做法:PHP魔术方法__set和__get
根据梅尔西(Melsi)的测试,相当慢的速度大约慢了5倍。这绝对慢得多,但是还要注意,测试表明,您仍然可以使用此方法访问属性10,000次,计算循环迭代的时间(大约1/100秒)。与定义的实际get和set方法相比,它要慢得多,这是一种轻描淡写的方法,但是从总体上看,即使慢5倍,也从未真正慢过。
在99%的实际应用中,运算的计算时间仍然可以忽略不计,不值得考虑。唯一应该避免的时间是您实际上将在单个请求中访问属性超过10,000次。如果高流量站点负担不起再增加一些服务器以保持其应用程序运行,那么它们的确在做错事。在访问率成为问题的高流量网站的页脚处放置一行文字广告,可能会为拥有该行文字的1000个服务器场支付费用。最终用户永远不会轻触自己的手指来思考加载页面所需的时间如此之久,因为您的应用程序的属性访问需要花费百万分之一秒的时间。
我说这是来自.NET的开发人员,但对于消费者而言,无形的get和set方法并不是.NET的发明。它们根本就是没有它们的属性,这些魔术方法是PHP开发人员的节省之选,甚至可以将它们的属性版本都称为“ properties”。此外,我认为,针对PHP的Visual Studio扩展确实支持具有受保护属性的智能感知,请牢记这一技巧。我认为,如果有足够的开发人员以这种方式使用神奇的__get和__set方法,PHP开发人员将调整执行时间以迎合开发人员社区。
编辑:从理论上讲,受保护的属性似乎可以在大多数情况下使用。实际上,事实证明,在访问类定义和扩展类中的属性时,很多时候您会想要使用getter和setter。更好的解决方案是扩展其他类时的基类和接口,因此您只需将几行代码从基类复制到实现类中即可。我要在项目的基类上做更多的事情,所以现在没有接口可以提供,但是这里是未经测试的精简类定义,其中魔术属性通过反射来设置和设置,以将属性移除并移动到受保护的数组:
class Component {
protected $properties = array();
public function __get($name) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
return $this->properties[$name]->value;
}
}
public function __set($name, $value) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
$this->properties[$name]->value = $value;
}
}
function __construct() {
$reflected_class = new ReflectionClass($this);
$properties = array();
foreach ($reflected_class->getProperties() as $property) {
if ($property->isStatic()) { continue; }
$properties[$property->name] = (object)array(
'name' => $property->name, 'value' => $property->value
, 'access' => $property->getModifier(), 'class' => get_class($this));
unset($this->{$property->name}); }
$this->properties = $properties;
}
}
如果代码中有任何错误,我深表歉意。