mirror of
https://github.com/DesignPatternsPHP/DesignPatternsPHP.git
synced 2025-05-31 02:57:29 +02:00
PHP7 Observer
This commit is contained in:
parent
b707bf064e
commit
9b9eee5a4c
@ -5,65 +5,16 @@ namespace DesignPatterns\Behavioral\Observer\Tests;
|
||||
use DesignPatterns\Behavioral\Observer\User;
|
||||
use DesignPatterns\Behavioral\Observer\UserObserver;
|
||||
|
||||
/**
|
||||
* ObserverTest tests the Observer pattern.
|
||||
*/
|
||||
class ObserverTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected $observer;
|
||||
|
||||
protected function setUp()
|
||||
public function testChangeInUserLeadsToUserObserverBeingNotified()
|
||||
{
|
||||
$this->observer = new UserObserver();
|
||||
}
|
||||
$observer = new UserObserver();
|
||||
|
||||
/**
|
||||
* Tests the notification.
|
||||
*/
|
||||
public function testNotify()
|
||||
{
|
||||
$this->expectOutputString('DesignPatterns\Behavioral\Observer\User has been updated');
|
||||
$subject = new User();
|
||||
$user = new User();
|
||||
$user->attach($observer);
|
||||
|
||||
$subject->attach($this->observer);
|
||||
$subject->property = 123;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the subscribing.
|
||||
*/
|
||||
public function testAttachDetach()
|
||||
{
|
||||
$subject = new User();
|
||||
$reflection = new \ReflectionProperty($subject, 'observers');
|
||||
|
||||
$reflection->setAccessible(true);
|
||||
/** @var \SplObjectStorage $observers */
|
||||
$observers = $reflection->getValue($subject);
|
||||
|
||||
$this->assertInstanceOf('SplObjectStorage', $observers);
|
||||
$this->assertFalse($observers->contains($this->observer));
|
||||
|
||||
$subject->attach($this->observer);
|
||||
$this->assertTrue($observers->contains($this->observer));
|
||||
|
||||
$subject->detach($this->observer);
|
||||
$this->assertFalse($observers->contains($this->observer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the update() invocation on a mockup.
|
||||
*/
|
||||
public function testUpdateCalling()
|
||||
{
|
||||
$subject = new User();
|
||||
$observer = $this->createMock('SplObserver');
|
||||
$subject->attach($observer);
|
||||
|
||||
$observer->expects($this->once())
|
||||
->method('update')
|
||||
->with($subject);
|
||||
|
||||
$subject->notify();
|
||||
$user->changeEmail('foo@bar.com');
|
||||
$this->assertCount(1, $observer->getChangedUsers());
|
||||
}
|
||||
}
|
||||
|
@ -3,60 +3,42 @@
|
||||
namespace DesignPatterns\Behavioral\Observer;
|
||||
|
||||
/**
|
||||
* Observer pattern : The observed object (the subject).
|
||||
*
|
||||
* The subject maintains a list of Observers and sends notifications.
|
||||
* User implements the observed object (called Subject), it maintains a list of observers and sends notifications to
|
||||
* them in case changes are made on the User object
|
||||
*/
|
||||
class User implements \SplSubject
|
||||
{
|
||||
/**
|
||||
* user data.
|
||||
*
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
protected $data = array();
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* observers.
|
||||
*
|
||||
* @var \SplObjectStorage
|
||||
*/
|
||||
protected $observers;
|
||||
private $observers;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->observers = new \SplObjectStorage();
|
||||
}
|
||||
|
||||
/**
|
||||
* attach a new observer.
|
||||
*
|
||||
* @param \SplObserver $observer
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function attach(\SplObserver $observer)
|
||||
{
|
||||
$this->observers->attach($observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* detach an observer.
|
||||
*
|
||||
* @param \SplObserver $observer
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function detach(\SplObserver $observer)
|
||||
{
|
||||
$this->observers->detach($observer);
|
||||
}
|
||||
|
||||
/**
|
||||
* notify observers.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changeEmail(string $email)
|
||||
{
|
||||
$this->email = $email;
|
||||
$this->notify();
|
||||
}
|
||||
|
||||
public function notify()
|
||||
{
|
||||
/** @var \SplObserver $observer */
|
||||
@ -64,21 +46,4 @@ class User implements \SplSubject
|
||||
$observer->update($this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ideally one would better write setter/getter for all valid attributes and only call notify()
|
||||
* on attributes that matter when changed.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->data[$name] = $value;
|
||||
|
||||
// notify the observers, that user has been updated
|
||||
$this->notify();
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,28 @@
|
||||
|
||||
namespace DesignPatterns\Behavioral\Observer;
|
||||
|
||||
/**
|
||||
* class UserObserver.
|
||||
*/
|
||||
class UserObserver implements \SplObserver
|
||||
{
|
||||
/**
|
||||
* This is the only method to implement as an observer.
|
||||
* It is called by the Subject (usually by SplSubject::notify() ).
|
||||
* @var User[]
|
||||
*/
|
||||
private $changedUsers = [];
|
||||
|
||||
/**
|
||||
* It is called by the Subject, usually by SplSubject::notify()
|
||||
*
|
||||
* @param \SplSubject $subject
|
||||
*/
|
||||
public function update(\SplSubject $subject)
|
||||
{
|
||||
echo get_class($subject).' has been updated';
|
||||
$this->changedUsers[] = clone $subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User[]
|
||||
*/
|
||||
public function getChangedUsers(): array
|
||||
{
|
||||
return $this->changedUsers;
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Diagram>
|
||||
<ID>PHP</ID>
|
||||
<OriginalElement>\DesignPatterns\Behavioral\Observer\User</OriginalElement>
|
||||
<nodes>
|
||||
<node x="239.0" y="0.0">\DesignPatterns\Behavioral\Observer\UserObserver</node>
|
||||
<node x="0.0" y="137.0">\DesignPatterns\Behavioral\Observer\User</node>
|
||||
<node x="8.0" y="0.0">\SplSubject</node>
|
||||
</nodes>
|
||||
<notes />
|
||||
<edges>
|
||||
<edge source="\DesignPatterns\Behavioral\Observer\User" target="\SplSubject">
|
||||
<point x="0.0" y="-74.0" />
|
||||
<point x="0.0" y="43.5" />
|
||||
</edge>
|
||||
</edges>
|
||||
<settings layout="Hierarchic Group" zoom="1.0" x="186.0" y="142.5" />
|
||||
<SelectedNodes />
|
||||
<Categories>
|
||||
<Category>Fields</Category>
|
||||
<Category>Constants</Category>
|
||||
<Category>Constructors</Category>
|
||||
<Category>Methods</Category>
|
||||
</Categories>
|
||||
<VISIBILITY>private</VISIBILITY>
|
||||
</Diagram>
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Diagram>
|
||||
<ID>PHP</ID>
|
||||
<OriginalElement>\DesignPatterns\Behavioral\Observer\UserObserver</OriginalElement>
|
||||
<nodes>
|
||||
<node x="215.0" y="112.0">\DesignPatterns\Behavioral\Observer\UserObserver</node>
|
||||
<node x="229.5" y="7.0">\SplObserver</node>
|
||||
<node x="-29.0" y="25.0">\DesignPatterns\Behavioral\Observer\User</node>
|
||||
</nodes>
|
||||
<notes />
|
||||
<edges>
|
||||
<edge source="\DesignPatterns\Behavioral\Observer\UserObserver" target="\SplObserver">
|
||||
<point x="0.0" y="-48.0" />
|
||||
<point x="0.0" y="25.5" />
|
||||
</edge>
|
||||
</edges>
|
||||
<settings layout="Hierarchic Group" zoom="1.0" x="58.0" y="91.0" />
|
||||
<SelectedNodes />
|
||||
<Categories>
|
||||
<Category>Fields</Category>
|
||||
<Category>Constants</Category>
|
||||
<Category>Methods</Category>
|
||||
</Categories>
|
||||
<VISIBILITY>private</VISIBILITY>
|
||||
</Diagram>
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 45 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 108 KiB |
Loading…
x
Reference in New Issue
Block a user