<?php
/** PHP Emulated JavaScript prototype behavior
* @author Andrea Giammarchi
* @site webreflection.blogspot.com
* @require runkit PECL extension
* @license Mit Style
*/
class prototype extends stdClass implements Iterator {
protected $_className = '', // class that will use prototype
$_methods = array(); // methods list
public function __construct(
/* string */ $className, // assign internal parameter
/* mixed */ $callbackList = null// optional list of callbacks or prototype to clone
){
if(!class_exists($this->_className = $className))
throw new Exception('Unable to assign a prototype to class '.$className);
if($callbackList)
foreach($callbackList as $name => $callback)
$this->$name = $callback;
}
public function __get(
/* string */ $name // which prototype method is required
){
return isset($this->_methods[$name]) ? $this->_methods[$name] : null;
}
public function __set(
/* string */ $name, // which prototype method is being assigned
array $callback = array() // method body, or method arguments plus body
){
if(count($callback) < 2)
array_unshift($callback, '');
if(
(
isset($this->_methods[$name]) &&
!runkit_method_redefine($this->_className, $name, $callback[0], $callback[1], RUNKIT_ACC_PUBLIC)
) ||
!runkit_method_add($this->_className, $name, $callback[0], $callback[1], RUNKIT_ACC_PUBLIC)
)
throw new Exception('Unable to define prototype->'.$name);
$this->_methods[$name] = $callback;
}
public function __unset(
/* string */ $name // which prototype is being removed
){
if(!runkit_method_remove($this->_className, $name))
throw new Exception('Unable to remove prototype->'.$name);
unset($this->_methods[$name]);
}
/** Iterator stuff */
public function current(){
return current($this->_methods);
}
public function key(){
return key($this->_methods);
}
public function next(){
return next($this->_methods);
}
public function rewind(){
return reset($this->_methods);
}
public function valid(){
return key($this->_methods) !== null;
}
}
?>