also lasst uns sagen, dass Sie nicht das Beobachter-Muster wollen, weil es erfordert, dass Sie Ihre Klassenmethoden ändern, um die Aufgabe des Zuhörens zu handhaben, und wollen etwas generisch. Nehmen wir an, Sie möchten nicht die Vererbung extends
verwenden, da Sie in Ihrer Klasse bereits von einer anderen Klasse erben. Wäre es nicht toll, einen generischen Weg zu haben, irgendeine Klasse steckbar ohne viel Aufwand zu machen? Hier ist, wie:
<?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;
In Teil 1, das ist, was Sie mit einem require_once()
Anruf an der Spitze Ihres PHP-Skripts enthalten könnten. Es lädt die Klassen, um etwas Pluggable zu machen.
In Teil 2 laden wir eine Klasse. Hinweis Ich musste der Klasse nichts Besonderes tun, was sich erheblich von dem Observer-Muster unterscheidet.
In Teil 3 verwandeln wir unsere Klasse in "steckbar" (das heißt, unterstützt Plugins, die Klassenmethoden und Eigenschaften überschreiben). Wenn Sie zum Beispiel eine Web-App haben, haben Sie möglicherweise eine Plugin-Registry, und Sie können hier Plugins aktivieren. Beachten Sie auch die Dog_bark_beforeEvent()
Funktion. Wenn ich $mixed = 'BLOCK_EVENT'
vor der Rückkehranweisung einstelle, blockiert es den Hund vom Bellen und würde auch das Dog_bark_afterEvent blockieren, weil es kein Ereignis geben würde.
In Teil 4 ist das der normale Operationscode, aber beachte, dass das, was du vielleicht denken würdest, nicht so läuft. Zum Beispiel gibt der Hund seinen Namen nicht als "Fido", sondern "Coco" bekannt. Der Hund sagt nicht "Miau", sondern "Wau". Und wenn Sie später den Namen des Hundes sehen wollen, finden Sie, dass es anders ist als "Coco". Alle diese Überschreibungen wurden in Teil 3 bereitgestellt.
Wie funktioniert das? Nun, lassen Sie uns eval()
ausschließen (was jeder sagt, ist "böse") und schließen aus, dass es kein Beobachter-Muster ist. Die Art und Weise, wie es funktioniert, ist die hinterhältige leere Klasse namens Pluggable, die die Methoden und Eigenschaften der Dog-Klasse nicht enthält. So, da dies geschieht, werden die magischen Methoden für uns eingreifen. Deshalb mischen wir in den Teilen 3 und 4 mit dem Objekt, das von der Pluggable-Klasse abgeleitet ist, und nicht von der Dog-Klasse selbst.Stattdessen lassen wir die Plugin-Klasse das "Berühren" des Dog-Objekts für uns ausführen. (Wenn das eine Art Designmuster ist, von dem ich nichts weiß - lass es mich wissen.)
Beachten Sie, dass Sie dies für PHP> = 5.0 mithilfe der Observer/Subject-Schnittstellen implementieren können, die in der SPL definiert sind: http://www.php.net/manual/en/class.plobserver.php –
Pedantic note: this is not an Beispiel für das Observer-Muster. Es ist ein Beispiel für das [Mediator Muster] (http://sourcemaking.com/design_patterns/mediator). Wahre Beobachter sind reine Benachrichtigung, es gibt keine Nachrichtenweitergabe oder bedingte Benachrichtigung (noch gibt es einen zentralen Manager zum Steuern von Benachrichtigungen). Es macht nicht die Antwort * falsch *, aber es sollte beachtet werden, dass Menschen Dinge mit dem falschen Namen aufrufen ... – ircmaxell
Beachten Sie, dass wenn Sie mehrere Hooks/Listeners verwenden, sollten Sie nur Zeichenfolgen oder Arrays, nicht beide zurückgeben. Ich habe etwas Ähnliches für Hound CMS implementiert - https://getbutterfly.com/hound/. – Ciprian