简单模仿js写法

<?php

/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2015/2/7
 * Time: 11:22
 */

trait Singletion {

	private static $instance;

	public static function instance() {
		self::$instance or self::$instance = new self;

		return self::$instance;
	}
}

trait MethodAble {

	private $methods;

	public function __construct() {
		$this->methods = new arrayObject;
	}

	public function setMethod( $handler, Closure $closure ) {
		if ( method_exists( $this, $handler ) || $this->methods->offsetExists( $handler ) ) {
			throw new Exception( "Cannot redeclare " . __CLASS__ . '::' . $handler, 1 );
		}
		$this->methods->offsetSet( $handler, $closure );

		return $this;
	}

	public function removeMethod( $handler ) {
		if ( $this->methods->offsetExists( $handler ) ) {
			$this->methods->offsetUnset( $handler );
		}
		return $this;
	}

	public function __call( $method, $args = array() ) {
		if ( isset( $this->methods[ $method ] ) && is_a( $this->methods[ $method ], 'Closure' ) ) {
			return call_user_func_array( Closure::bind( $this->methods[ $method ], $this ), $args );
		}

		return false;
	}

	public function getClosure( $handler ) {
		return isset( $this->methods[ $handler ] ) && is_a( $this->methods[ $handler ], 'Closure' ) ? $this->methods[ $handler ] : null;
	}
}

trait ServiceAble {

	private $service;

	public function __construct() {
		$this->service = ClassManager::make( 'Service', $this );
	}

	public function service() {
		return $this->service;
	}

	public function once( $handler, Closure $closure, $priority = 0 ){
		return $this->on( $handler, $closure, $priority, 1 );
	}

	public function on( $handler, Closure $closure, $priority = 0, $once = 0 ) {
		$this->service->attack( $handler, is_a($this, 'Prototype') ? $this->container : $this, $closure, $priority, $once );

		return $this;
	}

	public function off( $handler, $priority = null ) {
		$this->service->detack( $handler, $priority );

		return $this;
	}

	public function trigger( $handler, $data = null ) {
		return $this->service->trigger( $handler, $data );
	}
}

trait PrototypeAble {

	protected static $prototype;

	public function __construct() {
		static::$prototype = $this->prototype();
	}

	public function prototype() {
		return static::$prototype ? static::$prototype : ClassManager::make( 'Prototype', $this );
	}
}

class ClassManager {

	use Singletion;
	private $collections;

	private function __construct() {
		$this->collections or $this->collections = new ArrayObject();
	}

	public static function make( $class ) {
		$collections = self::instance()->collections;
		if ( $collections->offsetExists( $class ) ) {
			$class  = $collections->offsetGet( $class );
			$args   = func_get_args();
			$argNum = func_num_args();
			switch ( $argNum ) {
				case 2:
					return new $class( $args[1] );
					break;
				case 3:
					return new $class( $args[1], $args[2] );
					break;
				case 4:
					return new $class( $args[1], $args[2], $args[3] );
					break;
				case 5:
					return new $class( $args[1], $args[2], $args[3], $args[4] );
					break;
				case 6:
					return new $class( $args[1], $args[2], $args[3], $args[4], $args[5] );
					break;

				default:
					return new $class();
					break;
			}

		}

		return null;
	}

	public static function __callStatic( $func, $args ) {
		$collections = self::instance()->collections;
		if ( ! method_exists( $collections, $func ) ) {
			throw new Exception();
		}

		return call_user_func_array( array( $collections, $func ), $args );
	}
}

class Util {

	static function dump() {
		$dumps = func_get_args();
		ob_start();
		array_walk( $dumps, function ( $dump ) {
			var_dump( $dump );
		} );
		highlight_string( '<?php' . PHP_EOL . ob_get_clean() );
	}
}

class Collection extends SplObjectStorage {

}

class Event {

	private $handler;
	private $target;
	private $closure;
	private $priority;
	private $data;
	private $once;
	private $index;

	public function __construct( $handler, $target, $closure, $priority = 0, $once = 0 ) {
		$this->handler  = $handler;
		$this->target   = $target;
		$this->closure  = $closure;
		$this->priority = $priority;
		$this->once = $once;
		$this->index = null;
	}

	function setIndex( $index ) {
		$this->index = $index;

		return $this;
	}

	function setData( $data ) {
		$this->data = $data;

		return $this;
	}

	function __get( $key ) {
		return isset( $this->$key ) ? $this->$key : false;
	}
}

class Prototype {

	use MethodAble, ServiceAble {
		MethodAble::__construct as private __constructMethodAble;
		ServiceAble::__construct as private __constructServiceAble;
	}

	private $container;

	public function __construct( $container ) {
		$this->container = $container;
		$this->__constructMethodAble();
		$this->__constructServiceAble();
	}
}

class Service {

	private $eventCollections;
	private $component;

	public function __construct( $component ) {
		$this->component = $component;
	}

	public function attack( $handler, $component, Closure $closure, $priority = 0, $once = 0 ) {
		$priority                                          = $priority < 0 ? 0 : $priority;
		$this->eventCollections[ $handler ][ $priority ][] = ClassManager::make( 'Event', $handler, $component, $closure, $priority, $once );
		ksort( $this->eventCollections[ $handler ] );
	}

	public function detack( $handler, $priority = null ) {
		if ( null == $priority ) {
			unset( $this->eventCollections[ $handler ] );
		} else {
			unset( $this->eventCollections[ $handler ][ $priority ] );
		}
	}

	public function trigger( $handler, $data = null ) {
		if ( isset( $this->component->prototype()->service()->eventCollections[ $handler ] ) ) {
			array_walk_recursive( $this->component->prototype()->service()->eventCollections[ $handler ], function ( $event, $key ) use ( $handler ) {
				$event->once and $event->setIndex($key);
				$this->eventCollections[ $handler ][ $event->priority ][] = $event;
			} );
		}
		if ( isset( $this->eventCollections[ $handler ] ) ) {
			array_walk_recursive( $this->eventCollections[ $handler ], function ( $event, $key ) use ( $data, $handler ) {
				call_user_func( Closure::bind( $event->closure, $event->target ), $event->setData( $data ) );
				if( $event->once ){
					unset( $this->eventCollections[ $handler ][ $event->priority ][ $key ] );
					if( $event->index !== null ){
						unset( $this->component->prototype()->service()->eventCollections[ $handler ][ $event->priority ][ $event->index ] );
					}
				}
			} );
		}
	}
}

class Container {

	use MethodAble, ServiceAble, PrototypeAble {
		MethodAble::__construct as private __constructMethodAble;
		ServiceAble::__construct as private __constructServiceAble;
		PrototypeAble::__construct as private __constructPrototypeAble;
	}

	public function __construct() {
		$this->__constructMethodAble();
		$this->__constructServiceAble();
		$this->__constructPrototypeAble();
	}

	public function __call( $method, $args = array() ) {
		if ( isset( $this->methods[ $method ] ) && is_a( $this->methods[ $method ], 'Closure' ) ) {
			return call_user_func_array( Closure::bind( $this->methods[ $method ], $this ), $args );
		}
		if ( $closure = $this->prototype()->getClosure( $method ) ) {
			return call_user_func_array( Closure::bind( $closure, $this ), $args );
		}

		return false;
	}

}

class Component extends Container {

	protected static $prototype;

	function doSome() {
		$this->service()->trigger( 'doSome' );

		return $this;
	}
}

class Component2 extends Container {

	protected static $prototype;

	function doSome() {
		$this->service()->trigger( 'doSome' );

		return $this;
	}
}


if ( version_compare(PHP_VERSION, '5.4', '<') ) {
    throw new Exception('minimum version PHP 5.4.0, current version: ' . PHP_VERSION , 1);
}

$classMap = array( 'Util', 'Collection', 'Prototype', 'Container', 'Event', 'Service', 'Component' );
array_walk( $classMap, function ( $class ) {
	ClassManager::offsetSet( $class, $class );
} );

$component  = new Component;
$component2 = new Component;


$component->prototype()->setMethod( 'doSome4', function () {
	$this->trigger( 'doSome4', array( 'arg' ) );
} );
$component->setMethod( 'doSome2', function () {
	$this->trigger( 'doSome2' );
} );
$component2->setMethod( 'doSome3', function () {
	$this->trigger( 'doSome3' );
} );


$component->prototype()->once( 'doSome4', function ( $event ) {
	echo get_class($this) . '-'. $event->handler . '-' . $event->priority . '<br />';
}, 4 );
$component->prototype()->on( 'doSome4', function ( $event ) {
	echo get_class($this) . '-'. $event->handler . '-' . $event->priority . '<br />';
}, 3 );


$component->on( 'doSome', function ( $event ) {
	echo get_class($this) . '-'. $event->handler . '-' . $event->priority . '<br />';
}, 10 );
$component->on( 'doSome2', function ( $event ) {
	echo get_class($this) . '-'. $event->handler . '-' . $event->priority . '<br />';
}, 9 );
$component->on( 'doSome4', function ( $event ) {
	echo get_class($this) . '-'. $event->handler . '-' . $event->priority . '<br />';
}, 2 );


$component2->on( 'doSome', function ( $event ) {
	echo get_class($this) . '-'. $event->handler . '-' . $event->priority . '<br />';
}, 10 );
$component2->on( 'doSome3', function ( $event ) {
	echo get_class($this) . '-'. $event->handler . '-' . $event->priority . '<br />';
}, 11 );
$component2->on( 'doSome4', function ( $event ) {
	echo get_class($this) . '-'. $event->handler . '-' . $event->priority . '<br />';
}, 12 );


$component->removeMethod('doSome2');

$component->doSome();
$component->doSome2();
$component->doSome4();
echo '<hr />';
$component2->doSome();
$component2->doSome3();
$component2->doSome4();


你可能感兴趣的:(js,PHP)