I was just mocking up an intercept class I am working on. Idea is you instantiate the class through the Intercept class and then use that object as if it was the class you are intercepting. A specified callback is then run every time the class gets called. Here is the code:
<?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();
Now, running the code above should display 'world123'. But for some strange reason which I cannot see, it ends up timing out. I tried it on my local machine, and on various php 5.4 tester sites online. Same thing happens. I have narrowed it down to the closure being run ($this->callback()) in the run_callback() method. If i just remove the $this->callback(), it works fine. Why is this happening?
Edit, while I was writing this question, I figured out that instead of:
$this->callback();
Doing this will stop the timeout:
$closure = $this->callback;
$closure();
It seems that the __call method gets called everytime I try to run the closure directly from the class properties. Is this expected behaviour or have I stumbled apon a PHP bug?
Pretty sure it's because you have an infinite loop with the function call stack. When you do
$this->callback();
You're trying to execute the member function callback()
, which doesn't exist, so __call()
gets executed, which tries callback()
again, which doesn't exist, so __call()
gets executed, and so on and so forth.
You should be using something along the lines of:
call_user_func( $this->callback);
Or, like you've edited, this will work too:
$closure = $this->callback;
$closure();
Hopefully this clears up what is happening. The timeout is just occurring because you're running out of resources (in this case, time). The underlying problem is the infinite loop.