为什么一个空的__set()方法比一个有效的方法慢?

时间:2014-04-14 00:46:28

标签: php magic-methods microbenchmark

我正在使用PHP魔术方法(特别是Property overloading),并且,在进行微基准测试时遇到了一个奇怪的问题,我无法解释:

似乎一个空主体的__set方法比一个有效的方法需要更多时间。以下代码段演示了这一点:

class EmptySetter {
    public function __set($name, $value) {}
}

class NonEmptySetter {
    public function __set($name, $value) {
        $this->{$name} = $value;
    }
}

function benchmark($obj) {
    $start_time = microtime(TRUE);
    for ($i = 0; $i < 10000000; $i++) {
        $obj->foo = 42;
    }
    return microtime(TRUE) - $start_time;
}

printf("EmptySetter: %.2f seconds\n", benchmark(new EmptySetter));
printf("NonEmptySetter: %.2f seconds\n", benchmark(new NonEmptySetter));

// output (on my Core 2 Duo laptop):
// EmptySetter: 4.39 seconds
// NonEmptySetter: 1.28 seconds

有没有人解释为什么会这样?

2 个答案:

答案 0 :(得分:2)

你无法比较这两者,因为最终结果不相等。

$o1 = (new NonEmptySetter);
$o1->foo = 42;

$o2 = (new EmptySetter);
$o2->foo = 42;

var_dump($o1, $o2, $o2->foo);

这给出了:

object(NonEmptySetter)[1]
  public 'foo' => int 42

object(EmptySetter)[2]

null

并加上最后一个的通知:Notice: Undefined property: EmptySetter::$foo

这意味着属性永远不会设置,它不存在,仙尘,我假设需要时间的不规则。

enter image description here

如果您正确宣布您的课程(请注意$foo):

class EmptySetter {
    public $foo = NULL;
    public function __set($name, $value) {}
}

计时将被绑定:Your benchmark with EmptySetter::$foo declared

答案 1 :(得分:2)

哦,我认为这是错误的测试用例。

第一个循环NonEmptySetter之后会有新的公共属性foo。接下来的循环根本不会调用__set方法,它们使用公共属性。

class NonEmptySetter {
    public function __set($name, $value) {
        echo 'called only once'; // would be echoed only once.
        $this->{$name} = $value;
    }
}

有效测试

class EmptySetter {
    public function __set($name, $value) {}
}

class NonEmptySetter {
    public function __set($name, $value) {
        $this->{$name} = $value;
    }
}

function benchmark($class_name) {
    $start_time = microtime(TRUE);
    for ($i = 0; $i < 1000000; $i++) {
        $obj = new $class_name();
        $obj->foo = 42;
    }
    return microtime(TRUE) - $start_time;
}

printf("NonEmptySetter: %.2f seconds\n", benchmark('NonEmptySetter'));
printf("EmptySetter: %.2f seconds\n", benchmark('EmptySetter'));

http://3v4l.org/gVtSq

空的setter更快。