yehosef
9/22/2010 - 4:26 AM

oo.php

<?php

// Define the 'class' class
$class = Obj()
	->fn('new', function ($class) {
		$newClass = Obj($class->methods)
			->fn('new', function($class) {
				$obj = Obj($class->imethods);
				$args = func_get_args();
				array_shift($args);
				call_user_func_array(array($obj, 'init'), $args);
				return $obj;
			});
		return $newClass;
	})
	->fn('def', function ($t, $name, $fn) {
			$t->imethods[$name] = $fn;
			return $t;
	})
	->fn('extend', function ($t) {
			return clone $t;
	});

// Define a new class
$animal = $class->new()
	->def('init', function($t, $name) {
		$t->name = $name;
	})
	->def('speak', function($t) {
		echo "My name is $t->name\n";
	});

// Extend a class
$dog = $animal->extend()
	->def('speak', function($t) {
		echo "My name is $t->name, I have just met you and I love you, SQUIRREL!\n";
	})
	->def('bark', function($t) {
		echo "Woof!\n";
	});

$jimmy = $animal->new('Jimmy');
$jimmy->speak();

$doug = $dog->new('Doug');
$doug->speak();
$doug->bark();


// ---- The guts...

class Obj
{
	public function __construct($methods=array())
	{
		$this->methods = $methods;
	}

	public function method($name)
	{
		if (!isset($this->methods[$name]))
			throw new BadMethodCallException();

		return $this->methods[$name];
	}

	public function fn($name, $fn)
	{
		$this->methods[$name] = $fn;
		return $this;
	}

	public function __call($name, $args)
	{
		return call_user_func_array(
			$this->method($name),
			array_merge(array($this), $args)
		);
	}
}

// Allow chaining method calls off the constructor..
function Obj($methods=array())
{
	return new Obj($methods);
}