Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>So let's say you don't want the Observer pattern because it requires that you change your class methods to handle the task of listening, and want something generic. And let's say you don't want to use <code>extends</code> inheritance because you may already be inheriting in your class from some other class. Wouldn't it be great to have a generic way to make <em>any class pluggable without much effort</em>? Here's how:</p> <pre><code>&lt;?php //////////////////// // PART 1 //////////////////// class Plugin { private $_RefObject; private $_Class = ''; public function __construct(&amp;$RefObject) { $this-&gt;_Class = get_class(&amp;$RefObject); $this-&gt;_RefObject = $RefObject; } public function __set($sProperty,$mixed) { $sPlugin = $this-&gt;_Class . '_' . $sProperty . '_setEvent'; if (is_callable($sPlugin)) { $mixed = call_user_func_array($sPlugin, $mixed); } $this-&gt;_RefObject-&gt;$sProperty = $mixed; } public function __get($sProperty) { $asItems = (array) $this-&gt;_RefObject; $mixed = $asItems[$sProperty]; $sPlugin = $this-&gt;_Class . '_' . $sProperty . '_getEvent'; if (is_callable($sPlugin)) { $mixed = call_user_func_array($sPlugin, $mixed); } return $mixed; } public function __call($sMethod,$mixed) { $sPlugin = $this-&gt;_Class . '_' . $sMethod . '_beforeEvent'; if (is_callable($sPlugin)) { $mixed = call_user_func_array($sPlugin, $mixed); } if ($mixed != 'BLOCK_EVENT') { call_user_func_array(array(&amp;$this-&gt;_RefObject, $sMethod), $mixed); $sPlugin = $this-&gt;_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(&amp;$sHow) { echo "$sHow&lt;br /&gt;\n"; } public function sayName() { echo "&lt;br /&gt;\nMy Name is: " . $this-&gt;Name . "&lt;br /&gt;\n"; } } //end class Dog $Dog = new Dog(); //////////////////// // PART 3 //////////////////// $PDog = new Pluggable($Dog); function Dog_bark_beforeEvent(&amp;$mixed) { $mixed = 'Woof'; // Override saying 'meow' with 'Woof' //$mixed = 'BLOCK_EVENT'; // if you want to block the event return $mixed; } function Dog_bark_afterEvent(&amp;$mixed) { echo $mixed; // show the override } function Dog_Name_setEvent(&amp;$mixed) { $mixed = 'Coco'; // override 'Fido' with 'Coco' return $mixed; } function Dog_Name_getEvent(&amp;$mixed) { $mixed = 'Different'; // override 'Coco' with 'Different' return $mixed; } //////////////////// // PART 4 //////////////////// $PDog-&gt;Name = 'Fido'; $PDog-&gt;Bark('meow'); $PDog-&gt;SayName(); echo 'My New Name is: ' . $PDog-&gt;Name; </code></pre> <p>In Part 1, that's what you might include with a <code>require_once()</code> call at the top of your PHP script. It loads the classes to make something pluggable.</p> <p>In Part 2, that's where we load a class. Note I didn't have to do anything special to the class, which is significantly different than the Observer pattern.</p> <p>In Part 3, that's where we switch our class around into being "pluggable" (that is, supports plugins that let us override class methods and properties). So, for instance, if you have a web app, you might have a plugin registry, and you could activate plugins here. Notice also the <code>Dog_bark_beforeEvent()</code> function. If I set <code>$mixed = 'BLOCK_EVENT'</code> before the return statement, it will block the dog from barking and would also block the Dog_bark_afterEvent because there wouldn't be any event.</p> <p>In Part 4, that's the normal operation code, but notice that what you might think would run does not run like that at all. For instance, the dog does not announce it's name as 'Fido', but 'Coco'. The dog does not say 'meow', but 'Woof'. And when you want to look at the dog's name afterwards, you find it is 'Different' instead of 'Coco'. All those overrides were provided in Part 3.</p> <p>So how does this work? Well, let's rule out <code>eval()</code> (which everyone says is "evil") and rule out that it's not an Observer pattern. So, the way it works is the sneaky empty class called Pluggable, which does not contain the methods and properties used by the Dog class. Thus, since that occurs, the magic methods will engage for us. That's why in parts 3 and 4 we mess with the object derived from the Pluggable class, not the Dog class itself. Instead, we let the Plugin class do the "touching" on the Dog object for us. (If that's some kind of design pattern I don't know about -- please let me know.)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload