Supposons donc que vous ne vouliez pas du modèle Observer car il nécessite que vous modifiiez vos méthodes de classe pour gérer la tâche d'écoute et que vous vouliez quelque chose de générique. Et disons que vous ne voulez pas utiliser l' extends
héritage parce que vous héritez peut-être déjà dans votre classe d'une autre classe. Ne serait-il pas formidable d'avoir un moyen générique de rendre n'importe quelle classe enfichable sans trop d'effort ? Voici comment:
<?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;
Dans la partie 1, c'est ce que vous pourriez inclure avec un require_once()
appel en haut de votre script PHP. Il charge les classes pour rendre quelque chose enfichable.
Dans la partie 2, c'est là que nous chargeons une classe. Notez que je n'ai rien eu à faire de spécial pour la classe, ce qui est très différent du modèle Observer.
Dans la partie 3, c'est là que nous basculons notre classe pour qu'elle soit "enfichable" (c'est-à-dire, supporte les plugins qui nous permettent de remplacer les méthodes et les propriétés de la classe). Ainsi, par exemple, si vous avez une application Web, vous pouvez avoir un registre de plugins et vous pouvez activer les plugins ici. Remarquez également la Dog_bark_beforeEvent()
fonction. Si je mets $mixed = 'BLOCK_EVENT'
avant la déclaration de retour, cela empêchera le chien d'aboyer et bloquerait également Dog_bark_afterEvent car il n'y aurait aucun événement.
Dans la partie 4, c'est le code de fonctionnement normal, mais notez que ce que vous pourriez penser ne fonctionnerait pas du tout comme ça. Par exemple, le chien n'annonce pas son nom comme «Fido», mais «Coco». Le chien ne dit pas «miaou», mais «woof». Et quand vous voulez regarder le nom du chien par la suite, vous trouvez qu'il est «différent» au lieu de «Coco». Tous ces remplacements ont été fournis dans la partie 3.
Donc comment ça fonctionne? Eh bien, excluons eval()
(ce que tout le monde dit être "diabolique") et excluons que ce n'est pas un modèle Observateur. Ainsi, la façon dont cela fonctionne est la classe vide sournoise appelée Pluggable, qui ne contient pas les méthodes et les propriétés utilisées par la classe Dog. Ainsi, puisque cela se produit, les méthodes magiques vont s'engager pour nous. C'est pourquoi dans les parties 3 et 4, nous gâchons avec l'objet dérivé de la classe Pluggable, pas la classe Dog elle-même. Au lieu de cela, nous laissons la classe Plugin faire le "toucher" sur l'objet Dog pour nous. (Si c'est une sorte de modèle de conception que je ne connais pas - veuillez me le faire savoir.)