From the red-wine department: $this remains unresolved so of limited use, but some fun anyway:
class Extendable { static function import($context) { $self = new static(); while (is_callable($context)) $context = $context($self); if (is_array($context) || is_object($context) || is_a($context, 'Traversable')) { foreach($context as $key => $value) $self->$key = &$value; # preserve keys if } return $self; } public function __call($name, $args) { if (isset($this->$name) && is_callable($this->$name)) { return call_user_func_array($this->$name, $args); } throw new BadFunctionCallException(sprintf('Undefined function %s.', $name)); } } class Visitor extends Extendable { private $host; public function __construct($host) { $this->host = $host; } public function __get($member) { if (in_array($member, get_object_vars($this->host), true)) { return $this->host->$member; } throw new InvalidArgumentException(sprintf('Undefined variable "%s".', $member)); } public function __call($name, $args) { $host = $this->host; if (in_array($name, get_class_methods(get_class($host)))) return call_user_func_array(array($host, $name), $args); if (isset($host->$name) && is_callable($host->$name)) return call_user_func_array($host->$name, $args); parent::__call($name, $args); } } // extenable example: $test = new Extendable(); $test->test = function($text) {echo $text;}; $test->test('abc'); $seco = Extendable::import( array('test' => function($text) {echo $text;}) ); $seco->test('def'); $thir = Extendable::import($seco); $thir->test('ghi'); $thir->test = function() { echo 'new'; }; $thir->test('jkl'); // visitor example: class Test { private $tag = '1-2-3-TEST'; function dump() { var_dump($this); } function __toString() { return $this->tag; } } $test = new Test(); echo (string) $test, '<hr>'; $test = new Visitor($test); $test->test = function() {echo 'Test Called.';}; $test->test(); $test->dump(); var_dump($test);
And before you ask: It’s just that I was wondering the following did not work:
$test = new StdClass; $test->test = function($test) { echo $test; }; $test->test('abc'); // fatal error // or // $test2 = (object) array( 'test' => function($test) {echo $test;} )); $test2->test('def'); // fatal error
closures are reallly cool, no more create_functions.
And since stdClass is not a “PHP base class”, implements no interceptors and interfaces, theres no magic, we shouldn’t use it 😉