Así que digamos que usted no quiere que el patrón de observador, ya que requiere que cambie sus métodos de clase para manejar la tarea de escuchar, y quieren algo genérico. Y digamos que usted no desea utilizar extends
herencia porque usted ya puede estar heredando en su clase de alguna otra clase. ¿No sería bueno tener una forma genérica para hacer cualquier clase enchufable sin mucho esfuerzo? Así es como:
<?php
////////////////////
// PART 1
////////////////////
class Plugin {
private $_RefObject;
private $_Class = '';
public function __construct(&$RefObject) {
$this->_Class = get_class(&$RefObject);
$this->_RefObject = $RefObject;
}
public function __set($sProperty,$mixed) {
$sPlugin = $this->_Class . '_' . $sProperty . '_setEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
$this->_RefObject->$sProperty = $mixed;
}
public function __get($sProperty) {
$asItems = (array) $this->_RefObject;
$mixed = $asItems[$sProperty];
$sPlugin = $this->_Class . '_' . $sProperty . '_getEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
return $mixed;
}
public function __call($sMethod,$mixed) {
$sPlugin = $this->_Class . '_' . $sMethod . '_beforeEvent';
if (is_callable($sPlugin)) {
$mixed = call_user_func_array($sPlugin, $mixed);
}
if ($mixed != 'BLOCK_EVENT') {
call_user_func_array(array(&$this->_RefObject, $sMethod), $mixed);
$sPlugin = $this->_Class . '_' . $sMethod . '_afterEvent';
if (is_callable($sPlugin)) {
call_user_func_array($sPlugin, $mixed);
}
}
}
} //end class Plugin
class Pluggable extends Plugin {
} //end class Pluggable
////////////////////
// PART 2
////////////////////
class Dog {
public $Name = '';
public function bark(&$sHow) {
echo "$sHow<br />\n";
}
public function sayName() {
echo "<br />\nMy Name is: " . $this->Name . "<br />\n";
}
} //end class Dog
$Dog = new Dog();
////////////////////
// PART 3
////////////////////
$PDog = new Pluggable($Dog);
function Dog_bark_beforeEvent(&$mixed) {
$mixed = 'Woof'; // Override saying 'meow' with 'Woof'
//$mixed = 'BLOCK_EVENT'; // if you want to block the event
return $mixed;
}
function Dog_bark_afterEvent(&$mixed) {
echo $mixed; // show the override
}
function Dog_Name_setEvent(&$mixed) {
$mixed = 'Coco'; // override 'Fido' with 'Coco'
return $mixed;
}
function Dog_Name_getEvent(&$mixed) {
$mixed = 'Different'; // override 'Coco' with 'Different'
return $mixed;
}
////////////////////
// PART 4
////////////////////
$PDog->Name = 'Fido';
$PDog->Bark('meow');
$PDog->SayName();
echo 'My New Name is: ' . $PDog->Name;
En la Parte 1, eso es lo que se podría incluir en una llamada require_once()
en la parte superior de su script PHP. Carga las clases para hacer algo conectable.
En la Parte 2, ahí es donde cargamos una clase. Tenga en cuenta que no tuve que hacer nada especial para la clase, que es significativamente diferente al patrón Observer.
En la Parte 3, ahí es donde cambiamos nuestra clase en "conectable" (es decir, admite complementos que nos permiten anular las propiedades y los métodos de clase). Entonces, por ejemplo, si tiene una aplicación web, es posible que tenga un registro de complemento, y puede activar los complementos aquí. Observe también la función Dog_bark_beforeEvent()
. Si fijo $mixed = 'BLOCK_EVENT'
antes de la instrucción de retorno, bloqueará el perro ladrando y que también bloquean la Dog_bark_afterEvent porque no habría ningún evento.
En la Parte 4, ese es el código de operación normal, pero tenga en cuenta que lo que podría pensar que se ejecutaría no funciona de esa manera. Por ejemplo, el perro no anuncia su nombre como 'Fido', sino 'Coco'. El perro no dice 'miau', sino 'Guau'. Y cuando quieras mirar el nombre del perro después, encontrarás que es 'Diferente' en lugar de 'Coco'. Todas esas anulaciones se proporcionaron en la Parte 3.
Entonces, ¿cómo funciona esto? Bueno, descartemos eval()
(que todos dicen que es "malo") y descarte que no sea un patrón de Observador. Por lo tanto, la forma en que funciona es la clase vacía furtiva llamada Pluggable, que no contiene los métodos y las propiedades utilizadas por la clase Dog. Por lo tanto, dado que eso ocurre, los métodos mágicos se comprometerán con nosotros. Es por eso que en las partes 3 y 4 nos metimos con el objeto derivado de la clase Pluggable, no de la clase Dog.En su lugar, dejamos que la clase Plugin haga el "toque" en el objeto Dog para nosotros. (Si eso es una especie de patrón de diseño que no sé acerca de - por favor hágamelo saber.)
Tenga en cuenta que para PHP> = 5.0 puede implementar esto utilizando las interfaces Observer/Subject definidas en el SPL: http://www.php.net/manual/en/class.splobserver.php –
Nota pedante: esto no es un ejemplo del patrón Observer. Es un ejemplo de ['Mediator Pattern'] (http://sourcemaking.com/design_patterns/mediator). Los verdaderos observadores son puramente notificaciones, no hay mensajes que pasan ni notificaciones condicionales (ni existe un administrador central para controlar las notificaciones). No hace que la respuesta * sea incorrecta *, pero se debe tener en cuenta para evitar que las personas llamen cosas por el nombre incorrecto ... – ircmaxell
Tenga en cuenta que al usar múltiples ganchos/oyentes, solo debe devolver cadenas o matrices, no ambas. He implementado algo similar para Hound CMS - https://getbutterfly.com/hound/. – Ciprian