// podemos asignar prototipos en cualquier sitio ... JSObject::$prototype->getName = function($self){ return $self->name; }; $o = JSObject(); // ... incluso después de la creación de instancias de JSObject JSObject::$prototype->writeAge = function($self){ echo $self->getName().' tiene '.$self->age.' años.'; }; // asignar propiedades $o->name = 'Andrea'; $o->age = 30; // probar algún método JS echo $o->toJSONString(); // {"name":"Andrea","age":30} echo $o; // [object JSObject] echo $o->toSource(); // O:8:"JSObject":2:{s:4:"name";s:6:"Andrea";s:3:"age";i:30;} // o probar métodos en tiempo de ejecución $o->writeAge(); // Andrea tiene 30 años // podemos asignar un método personalizado en tiempo de ejecución $o->getSurname = function($self){ return 'Giammarchi'; }; // los métodos personalizados tienen prioridad sobre el prototipo $o->getName = function($self){ return $self->name.' '.$self->getSurname(); }; $o->writeAge(); // Andrea Giammarchi tiene 30 años. // no es hermoso? y aún falta más para la compatibilidad hacia atrás (backward): // prototipado via resolución de nombres de función JSObject::$prototype->getName = 'JSObject_getName'; // la función con un prefijo evita conflictos function JSObject_getName($self){ return $self->name; } // un simple caso de prueba $o = JSObject(); $o->name = 'Andrea'; echo $o->getName(); // Andrea // Y obviamente podemos hacer lo mismo con create_function: // prototype via lambda JSObject::$prototype->getName = create_function('$self',' return $self->name; ');
La implementación utiliza la extensión SPL disponible en el núcleo de PHP desde la versión 5.1:
/** js.php basic JSObject implementation * @author Andrea Giammarchi * @blog WebReflection.blogspot.com * @license Mit Style License */ class JSObject implements ArrayAccess { // public static prototype static public $prototype; // ArrayAccess Interface public function offsetExists($index){return isSet($this->$index);} public function offsetGet($index){return $this->$index;} public function offsetSet($index, $value){$this->$index = $value;} public function offsetUnset($index){unset($this->$index);} // Invoked lambdas via $this or self::$prototype public function __call($index, array $arguments){ // inject $this as first argument array_unshift($arguments, $this); // invoke the callback return call_user_func_array( // if it has been assigned to the object itself isset($this->$index) ? // it has priority $this->$index : // otherwise invoke from self::$prototype self::$prototype->$index , $arguments ); } // JS like behavior, ready for extends public function __toString(){ return '[object '.get_class($this).']'; // e.g. [object JSObject] } // Relevant Global Object implementations public function getPrototypeOf(){ return get_class($this); } public function hasOwnProperty($index){ return isset($this->$index); } public function isPrototypeOf(/* string */ $class){ return $this instanceof $class; } public function toSource(){ // we could implement __sleep and __wakeup // to avoid closure serialization (not possible yet) return serialize($this); } public function toString(){ return $this->__toString(); } // not standard method, anyway useful public function toJSONString(){ // we could parse properties in a foreach // to filter meaningless closures, if any return json_encode($this); } } // the global prototype is a JSObject too JSObject::$prototype = new JSObject; // JSObject factory: e.g. $myobj = JSObject(); // rather than new JSObject; function JSObject(){ return new JSObject($object); }
Como apunta Andrea, este puede ser el punto de partida para la creación de frameworks de PHP utilizando este estilo de programación. También menciona que unas extensiones estables de PECL que permitiesen una sobrecarga de operadores (de la que yo no soy muy amigo, por cierto) le permitiría crear una versión de PHP estilo JavaScript. Y aprovechar eso para conseguir que PHP se comporte como JavaScript en el lado del servidor al estilo Jaxer, pero utilizando PHP que está mucho más difundido.
WebReflection: [js.php] A JavaScript Object Like PHP Class.
No hay comentarios:
Publicar un comentario