【发布时间】:2012-02-18 15:41:56
【问题描述】:
我正在使用__get() 使我的一些属性“动态”(仅在请求时初始化它们)。这些“假”属性存储在私有数组属性中,我正在 __get 中检查。
无论如何,您认为为每个属性创建方法而不是在 switch 语句中创建方法更好吗?
编辑:速度测试
我只关心性能,@Gordon 提到的其他东西对我来说并不重要:
- 不必要的额外复杂性 - 它并没有真正增加我的应用复杂性
- 脆弱的非显而易见的 API - 我特别希望我的 API 被“隔离”;文档应该告诉其他人如何使用它:P
所以这是我所做的测试,这让我认为性能命中参数是不合理的:
50.000 次调用的结果(在 PHP 5.3.9 上):
(t1 = 带开关的魔法,t2 = getter,t3 = 带进一步 getter 调用的魔法)
不确定 t3 上的“Cum”是什么意思。它不能是累积时间,因为 t2 应该有 2K 那么...
代码:
class B{}
class A{
protected
$props = array(
'test_obj' => false,
);
// magic
function __get($name){
if(isset($this->props[$name])){
switch($name){
case 'test_obj':
if(!($this->props[$name] instanceof B))
$this->props[$name] = new B;
break;
}
return $this->props[$name];
}
trigger_error('property doesnt exist');
}
// standard getter
public function getTestObj(){
if(!($this->props['test_obj'] instanceof B))
$this->props['test_obj'] = new B;
return $this->props['test_obj'];
}
}
class AA extends A{
// magic
function __get($name){
$getter = "get".str_replace('_', '', $name); // give me a break, its just a test :P
if(method_exists($this, $getter))
return $this->$getter();
trigger_error('property doesnt exist');
}
}
function t1(){
$obj = new A;
for($i=1;$i<50000;$i++){
$a = $obj->test_obj;
}
echo 'done.';
}
function t2(){
$obj = new A;
for($i=1;$i<50000;$i++){
$a = $obj->getTestObj();
}
echo 'done.';
}
function t3(){
$obj = new AA;
for($i=1;$i<50000;$i++){
$a = $obj->test_obj;
}
echo 'done.';
}
t1();
t2();
t3();
ps:为什么我要使用 __get() 而不是标准的 getter 方法?唯一的原因是api美观;因为我没有看到任何真正的缺点,我想这是值得的:P
编辑:更多速度测试
这次我用 microtime 来测量一些平均值:
PHP 5.2.4 和 5.3.0(结果相似):
t1 - 0.12s
t2 - 0.08s
t3 - 0.24s
PHP 5.3.9,xdebug 处于活动状态,这就是它如此缓慢的原因:
t1 - 1.34s
t2 - 1.26s
t3- 5.06s
禁用 xdebug 的 PHP 5.3.9:
t1 - 0.30
t2 - 0.25
t3 - 0.86
另一种方法:
// magic
function __get($name){
$getter = "get".str_replace('_', '', $name);
if(method_exists($this, $getter)){
$this->$name = $this->$getter(); // <-- create it
return $this->$name;
}
trigger_error('property doesnt exist');
}
在第一次 __get 调用之后,将动态创建具有请求名称的公共属性。这解决了速度问题 - 在 PHP 5.3 中获得 0.1 秒(它比标准 getter 快 12 倍),以及 Gordon 提出的可扩展性问题。您可以简单地覆盖子类中的 getter。
缺点是属性变得可写:(
【问题讨论】:
-
在这些测试中,“cum”是函数花费的时间,包括从内部调用的任何函数的时间(基本上是从函数开始执行到它返回)。这与“self”时间不同,后者在调用其他函数时有效地“暂停”计时器。在这种情况下,t3 的 "cum" 减去 "self" 计算出在 $this->$getter() 调用中花费了多少时间,而 "self" 是它执行其他操作所花费的时间__get() 函数。
标签: php performance oop