air*_*ear 82 php magic-methods
除非我完全弄错了,否则这些__get和__set方法应该允许重载→ get和set.
例如,以下语句应调用该__get方法:
echo $foo->bar;
$var = $foo->bar;
Run Code Online (Sandbox Code Playgroud)
以下应该使用该__set方法:
$foo->bar = 'test';
Run Code Online (Sandbox Code Playgroud)
这在我的代码中不起作用,并且可以通过这个简单的示例重现:
class foo {
public $bar;
public function __get($name) {
echo "Get:$name";
return $this->$name;
}
public function __set($name, $value) {
echo "Set:$name to $value";
$this->$name = $value;
}
}
$foo = new foo();
echo $foo->bar;
$foo->bar = 'test';
echo "[$foo->bar]";
Run Code Online (Sandbox Code Playgroud)
这只会导致:
[test]
Run Code Online (Sandbox Code Playgroud)
die()在那里打几个电话表明它根本没有打它.
现在,我只是说它,并且我手动使用__get它现在需要的地方,但这不是非常动态,并且需要知道"重载"代码实际上没有被调用,除非特别调用.我想知道这是不应该以我理解它应该或为什么这不起作用的方式起作用.
这是在运行php 5.3.3.
Gor*_*don 153
__get,__set,__call和__callStatic当该方法或属性是不可访问的被调用.你$bar是公开的,因此不可访问.
__set()在将数据写入不可访问的属性时运行.__get()用于从不可访问的属性中读取数据.
魔术方法不能替代getter和setter.它们只允许您处理方法调用或属性访问,否则会导致错误.因此,与错误处理有更多相关.另请注意,它们比使用正确的getter和setter或直接方法调用慢得多.
Ale*_*ich 32
我建议使用数组来存储所有值__set().
class foo {
protected $values = array();
public function __get( $key )
{
return $this->values[ $key ];
}
public function __set( $key, $value )
{
$this->values[ $key ] = $value;
}
}
Run Code Online (Sandbox Code Playgroud)
这样您就可以确保不能以其他方式访问变量(注意$values受保护),以避免冲突.
小智 6
为了扩展Berry的答案,将访问级别设置为protected允许__get和__set与显式声明的属性一起使用(至少在类外部访问时),并且速度相当慢,我将引用另一个问题的注释关于这个主题,并提出使用它的案例:
我同意__get对自定义get函数更慢(做同样的事情),这是__get()的时间是0.0124455,而这个0.0024445是10000循环后的自定义get().- Melsi 12年11月23日在22:32 最佳实践:PHP Magic Methods __set和__get
根据Melsi的测试,相当慢的速度大约慢5倍.这肯定要慢得多,但同时请注意,测试显示您仍然可以使用此方法访问属性10,000次,计算循环迭代的时间,大约是1/100秒.与定义的实际get和set方法相比,它要慢得多,这是轻描淡写,但在宏观方案中,即使慢5倍也从来没有实际上很慢.
该操作的计算时间仍然可以忽略不计,并且在99%的实际应用中不值得考虑.真正应该避免的唯一一次是你实际上要在一次请求中访问属性超过10,000次.如果他们无法承担更多的服务器以保持他们的应用程序运行,那么高流量站点正在做一些非常错误的事情.高流量站点的页脚上的单行文本广告(访问率成为问题)可能需要支付具有该行文本的1,000个服务器的服务器场.最终用户永远不会被窃听他们的手指想知道走的是页面这么长时间加载,因为应用程序的属性访问需要百万分之一秒的.
我说这是一个来自.NET背景的开发人员,但对于消费者来说,隐形的get和set方法并不是.NET的发明.它们不是没有它们的属性,而这些神奇的方法是PHP的开发人员甚至可以节省它们的属性"属性"的版本.此外,PHP的Visual Studio扩展确实支持带有受保护属性的intellisense,我想这就是这个技巧.我想用这样的魔力__get和__set方法足够的开发人员来说,PHP开发者调补的执行时间,以满足开发者社区.
编辑:理论上,受保护的属性似乎在大多数情况下都有效.实际上,事实证明,在访问类定义和扩展类中的属性时,很多时候您会想要使用getter和setter.更好的解决方案是扩展其他类时的基类和接口,因此您只需将几行代码从基类复制到实现类中即可.我正在使用我的项目的基类做更多的事情,所以我现在没有提供的接口,但是这里是未经测试的剥离类定义,使用magic属性获取并使用反射来设置删除并将属性移动到受保护的数组:
/** Base class with magic property __get() and __set() support for defined properties. */
class Component {
/** Gets the properties of the class stored after removing the original
* definitions to trigger magic __get() and __set() methods when accessed. */
protected $properties = array();
/** Provides property get support. Add a case for the property name to
* expand (no break;) or replace (break;) the default get method. When
* overriding, call parent::__get($name) first and return if not null,
* then be sure to check that the property is in the overriding class
* before doing anything, and to implement the default get routine. */
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;
}
}
/** Provides property set support. Add a case for the property name to
* expand (no break;) or replace (break;) the default set method. When
* overriding, call parent::__set($name, $value) first, then be sure to
* check that the property is in the overriding class before doing anything,
* and to implement the default set routine. */
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;
}
}
/** Constructor for the Component. Call first when overriding. */
function __construct() {
// Removing and moving properties to $properties property for magic
// __get() and __set() support.
$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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果代码中有任何错误,我很抱歉.
这是因为$ bar是公共财产。
$foo->bar = 'test';
Run Code Online (Sandbox Code Playgroud)
运行以上命令时无需调用magic方法。
public $bar;从班级删除应该更正此问题。