Deci, să presupunem că nu doriți modelul Observer deoarece trebuie să vă schimbați metodele de clasă pentru a vă ocupa de sarcina de a asculta și doriți ceva generic. Și să presupunem că nu doriți să utilizați moștenire extinde
, deoarece probabil ați moștenit deja în clasa dvs. din altă clasă. Nu ar fi grozav să existe o modalitate generică de a face orice clasă conectabilă fără prea mult efort ? Iată cum:
<?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
\n";
}
public function sayName() {
echo "
\nMy Name is: " . $this->Name . "
\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;
În Partea 1, asta ar trebui să includeți cu un apel require_once()
în partea de sus a scriptului dvs. PHP. Încarcă clasele pentru a face ceva conectabil.
În Partea a 2-a, aici încărcăm o clasă. Rețineți că nu trebuie să fac nimic special pentru clasă, care este semnificativ diferit de modelul Observer.
În partea a 3-a, aceasta este locul în care ne schimbăm clasa în jurul valorii de a fi "pluggable" (adică, acceptă pluginuri care ne permit să suprascrieți metodele de clasă și proprietățile). De exemplu, dacă aveți o aplicație web, este posibil să aveți un registru de pluginuri și puteți să activați pluginurile aici. Observați și funcția Dog_bark_beforeEvent()
. Dacă am setat $ mixed = 'BLOCK_EVENT'
înainte de declarația de întoarcere, acesta va bloca câinele din latră și ar bloca, de asemenea, Dog_bark_afterEvent deoarece nu ar fi niciun eveniment.
În Partea 4, acesta este codul normal de funcționare, dar observați că ceea ce ați putea crede că ar funcționa nu se execută deloc. De exemplu, câinele nu anunță numele lui ca "Fido", ci "Coco". Câinele nu spune "miau", ci "Woof". Și când doriți să vă uitați la numele câinelui după aceea, veți găsi că este "Different" în loc de "Coco". Toate aceste înlocuiri au fost furnizate în partea 3.
Deci, cum funcționează acest lucru? Ei bine, să excludem eval()
(pe care toată lumea spune că este "rău") și să excludă că nu este un model de Observer. Deci, modul în care funcționează este clasa goală mascată numită Pluggable, care nu conține metodele și proprietățile folosite de clasa Dog. Astfel, din moment ce aceasta se întâmplă, metodele magice se vor angaja pentru noi. De aceea, în părțile 3 și 4 ne confruntăm cu obiectul derivat din clasa Pluggable, și nu de clasa Dogului în sine. În schimb, lăsăm clasa Plugin să facă "atingerea" obiectului Dog pentru noi. (Dacă asta e un tip de model de design despre care nu știu - te rog să-mi spui.)