PHP: Extending stdClass with Closures (plus Visitor)

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
This entry was posted in PHP Development, Pressed and tagged , . Bookmark the permalink.

One Response to PHP: Extending stdClass with Closures (plus Visitor)

  1. pe says:

    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😉

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s