3.8. Opletter
3.8.1. Doel
Om een publicatie- / abonneergedrag voor een object te implementeren, worden de bijgevoegde “Waarnemers” op de hoogte gesteld wanneer een “Onderwerp” -object van status verandert. Het wordt gebruikt om het aantal gekoppelde objecten te verkorten en gebruikt in plaats daarvan een losse koppeling.
3.8.2. Bijvoorbeeld
een berichtenwachtrijsysteem wordt geobserveerd om de voortgang van een taak in een GUI te tonen
3.8.3. Notitie
PHP definieert al twee interfaces die kunnen helpen om dit patroon te implementeren: SplWaarnemer en SplOnderwerp.
3.8.4. UML Diagram

3.8.5. Code
Je kan deze broncode terugvinden op GitHub
User.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\Observer;
6
7use SplSubject;
8use SplObjectStorage;
9use SplObserver;
10
11/**
12 * User implements the observed object (called Subject), it maintains a list of observers and sends notifications to
13 * them in case changes are made on the User object
14 */
15class User implements SplSubject
16{
17 private SplObjectStorage $observers;
18 private $email;
19
20 public function __construct()
21 {
22 $this->observers = new SplObjectStorage();
23 }
24
25 public function attach(SplObserver $observer): void
26 {
27 $this->observers->attach($observer);
28 }
29
30 public function detach(SplObserver $observer): void
31 {
32 $this->observers->detach($observer);
33 }
34
35 public function changeEmail(string $email): void
36 {
37 $this->email = $email;
38 $this->notify();
39 }
40
41 public function notify(): void
42 {
43 /** @var SplObserver $observer */
44 foreach ($this->observers as $observer) {
45 $observer->update($this);
46 }
47 }
48}
UserObserver.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\Observer;
6
7use SplObserver;
8use SplSubject;
9
10class UserObserver implements SplObserver
11{
12 /**
13 * @var SplSubject[]
14 */
15 private array $changedUsers = [];
16
17 /**
18 * It is called by the Subject, usually by SplSubject::notify()
19 */
20 public function update(SplSubject $subject): void
21 {
22 $this->changedUsers[] = clone $subject;
23 }
24
25 /**
26 * @return SplSubject[]
27 */
28 public function getChangedUsers(): array
29 {
30 return $this->changedUsers;
31 }
32}
3.8.6. Test
Tests/ObserverTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace DesignPatterns\Behavioral\Observer\Tests;
6
7use DesignPatterns\Behavioral\Observer\User;
8use DesignPatterns\Behavioral\Observer\UserObserver;
9use PHPUnit\Framework\TestCase;
10
11class ObserverTest extends TestCase
12{
13 public function testChangeInUserLeadsToUserObserverBeingNotified()
14 {
15 $observer = new UserObserver();
16
17 $user = new User();
18 $user->attach($observer);
19
20 $user->changeEmail('foo@bar.com');
21 $this->assertCount(1, $observer->getChangedUsers());
22 }
23}