<?php
namespace CHH;
trait MetaObject
{
protected static $__metaClass;
static function setMetaClass(MetaClass $metaClass)
{
static::$__metaClass = $metaClass;
}
static function getMetaClass()
{
if (null === static::$__metaClass) {
static::$__metaClass = new MetaClass;
}
return static::$__metaClass;
}
function __call($method, array $argv = array())
{
$metaClass = static::getMetaClass();
if (!$metaClass->respondsTo($method)) {
throw new \BadMethodCallException(sprintf(
'Call to undefined method %s', $method
));
}
return $metaClass->send($method, $argv, $this);
}
function __get($property)
{
$metaClass = static::getMetaClass();
if (property_exists($metaClass, $property)) {
return $this->$property = $metaClass->$property;
}
}
function __isset($property)
{
return property_exists(static::getMetaClass(), $property);
}
}
class MetaClass
{
protected $methods = array();
function extend($methods)
{
if ($methods instanceof MetaClass) {
$methods = $methods->getMethods();
}
foreach ($methods as $method => $body) {
$this->method($method, $body);
}
return $this;
}
function getMethods()
{
return $this->methods;
}
function method($name, \Closure $body)
{
$this->methods[$name] = $body;
return $this;
}
function property($name, $default = null)
{
$this->{$name} = $default;
return $this;
}
function respondsTo($method)
{
return isset($this->methods[$method]);
}
function send($method, array $argv = array(), $context = null)
{
if (!$this->respondsTo($method)) {
throw new \BadMethodCallException("Call to undefined Method $method");
}
$body = $this->methods[$method];
if (null !== $context) {
$body = $body->bindTo($context, get_class($context));
}
return call_user_func_array($body, $argv);
}
}