PHP 5.4次调用关闭

时间:2013-02-12 02:24:47

标签: php oop timeout closures interceptor

我只是在嘲笑我正在进行的拦截课程。想法是通过Intercept类实例化该类,然后使用该对象,就像它是您正在拦截的类一样。每次调用类时都会运行指定的回调。这是代码:

<?php
class Intercept {

    protected $class = null;
    protected $callback = null;

    public function __construct($class, $callback = null) {

        $this->class = new $class();
        $this->callback = $callback;
    }

    protected function run_callback() {

        $this->callback();
    }

    public function __get($name) {

        $this->run_callback();
        return $this->class->$name;
    }

    public function __set($name, $value) {

        $this->run_callback();      
        return $this->class->$name = $value;
    }

    public function __isset($name) {

        $this->run_callback();
        return isset($this->class->$name);
    }

    public function __unset($name) {

        $this->run_callback();
        unset($this->class->$name);
    }

    public function __call($method, $args) {

        $this->run_callback();
        return call_user_func_array(array($this->class, $method), $args);
    }

    public function __toString() {

        $this->run_callback();
        return $this->class;
    }

    public function __invoke() {

        $this->run_callback();
        return $this->class();
    }
}

class test {
    public function hello() { 
        return 'world'; 
    }
}

$closure = function() {
    echo 123;
};

$test=new Intercept('test', $closure);
echo $test->hello();

现在,运行上面的代码应该显示'world123'。但是由于一些我看不到的奇怪的原因,它最终会超时。我在我的本地机器上以及在线的各种php 5.4测试站点上尝试过它。同样的事情发生了我已经将它缩小到run_callback()方法中运行的闭包($ this-&gt; callback())。如果我只是删除$ this-&gt; callback(),它可以正常工作。为什么会这样?

编辑,在我写这个问题的时候,我发现了,而不是:

$this->callback();

这样做会停止超时:

$closure = $this->callback;
$closure();

似乎每次我尝试直接从类属性运行闭包时都会调用__call方法。这是预期的行为还是我偶然发现了PHP错误?

1 个答案:

答案 0 :(得分:4)

很确定这是因为你有一个函数调用堆栈的无限循环。当你这样做

$this->callback();

您正在尝试执行不存在的成员函数callback(),因此__call()会被执行,再次尝试callback(),这不存在,所以{ {1}}被执行,依此类推。

你应该使用以下内容:

__call()

或者,就像你编辑过的那样,这也会起作用:

call_user_func( $this->callback);

希望这可以清除正在发生的事情。超时刚刚发生,因为您的资源不足(在这种情况下,时间)。潜在的问题是无限循环。