Entonces, digamos que no desea el patrón Observador porque requiere que cambie los métodos de su clase para manejar la tarea de escuchar y desee algo genérico. Y supongamos que no desea usar la extends
herencia porque ya puede estar heredando en su clase de otra clase. ¿No sería genial tener una forma genérica de hacer que cualquier clase se pueda conectar sin mucho esfuerzo ? Así es cómo:
<?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 puede incluir con una require_once()
llamada 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 del Observador.
En la Parte 3, ahí es donde cambiamos nuestra clase para que sea "conectable" (es decir, admite complementos que nos permiten anular los métodos y propiedades de la clase). Entonces, por ejemplo, si tiene una aplicación web, es posible que tenga un registro de complementos, y podría activar los complementos aquí. Observe también la Dog_bark_beforeEvent()
función. Si configuro $mixed = 'BLOCK_EVENT'
antes de la declaración de devolución, bloqueará al perro para que no ladre y también bloqueará el 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 así en absoluto. Por ejemplo, el perro no anuncia su nombre como 'Fido', sino 'Coco'. El perro no dice "miau", sino "Guau". Y cuando desee ver el nombre del perro después, encontrará que es 'Diferente' en lugar de 'Coco'. Todas esas anulaciones se proporcionaron en la Parte 3.
Entonces, ¿cómo funciona esto? Bueno, descartemos eval()
(lo que todos dicen que es "malvado") y descartemos que no sea un patrón de Observador. Entonces, la forma en que funciona es la clase vacía disimulada llamada Pluggable, que no contiene los métodos y propiedades utilizados por la clase Dog. Por lo tanto, ya que eso ocurre, los métodos mágicos nos comprometerán. Es por eso que en las partes 3 y 4 nos metemos con el objeto derivado de la clase Pluggable, no con la clase Dog en sí. En cambio, dejamos que la clase Plugin haga el "toque" en el objeto Dog por nosotros. (Si ese es algún tipo de patrón de diseño que no conozco, hágamelo saber).