Quindi diciamo che non vuoi il modello Observer perché richiede che tu modifichi i metodi della tua classe per gestire l'attività di ascolto e desideri qualcosa di generico. E diciamo che non vuoi usare l' extends
ereditarietà perché potresti già ereditare nella tua classe da un'altra classe. Non sarebbe bello avere un modo generico per rendere collegabile qualsiasi classe senza troppi sforzi ? Ecco come:
<?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;
Nella parte 1, ecco cosa potresti includere con una require_once()
chiamata nella parte superiore dello script PHP. Carica le classi per rendere collegabile qualcosa.
Nella parte 2, è qui che si carica una classe. Nota non ho dovuto fare nulla di speciale per la classe, che è significativamente diversa dal modello Observer.
Nella parte 3, è qui che trasformiamo la nostra classe in "innestabile" (ovvero, supporta i plug-in che ci consentono di ignorare i metodi e le proprietà della classe). Ad esempio, se disponi di un'app Web, potresti avere un registro dei plug-in e qui puoi attivare i plug-in. Notare anche la Dog_bark_beforeEvent()
funzione. Se avessi impostato $mixed = 'BLOCK_EVENT'
prima dell'istruzione return, questo avrebbe impedito al cane di abbaiare e avrebbe anche bloccato Dog_bark_afterEvent perché non ci sarebbero stati eventi.
Nella parte 4, questo è il normale codice operativo, ma nota che ciò che potresti pensare non funzionerebbe affatto. Ad esempio, il cane non annuncia il suo nome come "Fido", ma "Coco". Il cane non dice "miagolio", ma "Woof". E quando vuoi guardare il nome del cane in seguito, scopri che è "Diverso" anziché "Coco". Tutte queste sostituzioni sono state fornite nella Parte 3.
Quindi come funziona? Bene, escludiamo eval()
(che tutti dicono sia "malvagio") e escludiamo che non sia un modello di osservatore. Quindi, il modo in cui funziona è la subdola classe vuota chiamata Pluggable, che non contiene i metodi e le proprietà utilizzate dalla classe Dog. Quindi, dato che ciò accade, i metodi magici si impegneranno per noi. Ecco perché nelle parti 3 e 4 pasticciamo con l'oggetto derivato dalla classe Pluggable, non dalla classe Dog stessa. Invece, lasciamo che la classe Plugin faccia il "toccante" sull'oggetto Dog per noi. (Se questo è un tipo di modello di progettazione che non conosco - per favore fatemi sapere.)