PHP observer pattern si SPL
Observer pattern se refera la un obiect “subiect” care are asociata o lista de obiecte dependente, numite observatori, pe care le apeleaza automat de fiecare data cand se intampla o actiune.
Un mic exemplu de ce se foloseste:
– sa zicem ca avem o clasa pe care se fac niste modificari:
1class Actiune {
2 private $val;
3 function __construrct() {
4 // ceva cod in constructor
5 }
6
7 function change($val) {
8 $this->val = $val;
9 }
10}
De fiecare data cand se face modifica $val vrem sa se apeleze o metoda a unui obiect “observator”:
1class Actiune {
2 private $val;
3 function __construrct() {
4 // ceva cod in constructor
5 }
6
7 function change($val, $observator) {
8 $this->val = $val;
9 $observator->update($this);
10 }
11}
Teoretic nu suna rau, dar cu cat sunt mai multe metode cu atat exista o dependenta mai mare si de fiecare data cand se adauga un obiect nou de tip observator trebuie modificata clasa, avand toate sansele sa rezulte intr-un haos aproape imposibil de portat.
Acum observator pattern arata cam asa:
SPL (Standard PHP Library), care este bine cunoscut pentru iteratorii definiti, vine cu interfetele SplSubject si SplObserver, pentru subiect respectiv observator.
O implementare arata cam asta:
1/**
2 * clasa care trebuie urmarita
3 */
4class Actiune implements SplSubject {
5 private $observatori = array();
6 private $val;
7
8 /**
9 * metoda atasare obiect observator
10 *
11 * @param SplObserver $observator
12 */
13 function attach(SplObserver $observator) {
14 $this->observatori[] = $observator;
15 }
16
17 /**
18 * metoda deatasare obiect observator
19 *
20 * @param SplObserver $observator
21 */
22 function detach(SplObserver $observator) {
23 $observatori = array();
24 foreach($this->observatori as $observatorul) {
25 if($observatorul != $observator) $observatori[] = $observatorul;
26 }
27 $this->observatori = $observatori;
28 }
29
30 /**
31 * metoda care notifica obiectele de tip observator
32 */
33 function notify() {
34 foreach($this->observatori as $observator) {
35 $observator->update($this);
36 }
37 }
38
39 /**
40 * metoda care face modificarea in clasa
41 *
42 * @param int $val
43 */
44 function update($val) {
45 echo 'facem update...
46';
47 $this->val = $val;
48 $this->notify();
49 }
50
51 /**
52 * metoda publica care intoarce statusul obiectului
53 *
54 * @return int
55 */
56 function getStatus() {
57 return $this->val;
58 }
59}
60
61/**
62 * o clasa observator
63 */
64class Observator implements SplObserver {
65 function update(SplSubject $subiect) {
66 echo $subiect->getStatus();
67 }
68}
69
70// instanta observator
71$observator = new Observator();
72
73// instanta subiect
74$subiect = new Actiune();
75
76// atasare observator la subiect
77$subiect->attach($observator);
78
79// update subiect
80$subiect->update(5);
Ce mi se pare mie ciudat este ca nu exista o documentatie pentru aceste interfetele din SPL. Chiar pe site-ul zend exista un articol PHP Patterns: The Observer Pattern care nu foloseste SPL, iar asta in masura in care exista documentatie pentru namespaces chiar inainte sa apara PHP 5.3.