PHP observer pattern si SPL

Read this post in English

Share on:

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:

diagrama

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.