<?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); } }