Skip to content

Instantly share code, notes, and snippets.

@tonyseek
Created June 18, 2012 07:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tonyseek/2947376 to your computer and use it in GitHub Desktop.
Save tonyseek/2947376 to your computer and use it in GitHub Desktop.
Implementing observer pattern in PHP >= 5.4
<?php
require_once 'observer.php';
require_once 'subject.php';
use Common\Observer\Observer;
use Common\Observer\Subject;
class Notice
{
use Subject;
/**
* The title
* @var string
*/
private $title = '';
/**
* The notice content
* @var unknown_type
*/
private $content = '';
/**
* The last modified time
* @var unknown_type
*/
private $lastModified = null;
/**
* The constructor
*/
public function __construct($title, $content)
{
$this->title = $title;
$this->content = $content;
$this->lastModified = new DateTime();
}
public function __get($attribute)
{
return $this->$attribute;
}
public function __set($attribute, $value)
{
$this->lastModified = new DateTime();
$this->$attribute = $value;
$this->notify(); // notify all observers have be registered to this instance
}
}
class NoticeBoard implements Observer
{
private function drawSingleLine($char='-', $repeat=80)
{
while($repeat--) {
echo $char;
}
echo '<br />';
}
public function display($notice)
{
$this->drawSingleLine();
echo "Title: {$notice->title}" . '<br />';
echo "Content: {$notice->content}" . '<br />';
echo "Last Modified At: {$notice->lastModified->format('Y-m-d H:i:s')}" . '<br />';
$this->drawSingleLine();
}
public function update($subject)
{
$this->drawSingleLine('=');
echo '<strong>' . '[A notice has been updated]' . '</strong>';
echo "The notice '{$subject->title}' has been modified." . '<br />';
echo "New Content: {$subject->content}" . '<br />';
echo "Last Modified At: {$subject->lastModified->format('Y-m-d H:i:s')}" . '<br />';
$this->drawSingleLine('=');
}
}
/**
* Let the notice be displayed again while it being modified.
*
* @author TonySeek
*
*/
class NoticeDisplayAgainWhileModifying implements Observer
{
public function __construct($board)
{
$this->board = $board;
}
public function update($subject)
{
$this->board->display($subject);
}
}
$notice = new Notice('Be careful', 'This is a dangerous behavior.');
$board = new NoticeBoard();
$displayAgain = new NoticeDisplayAgainWhileModifying($board);
$notice->attachObserver($board);
$notice->attachObserver($displayAgain); // try to remove this line
// the first display
$board->display($notice);
// modified the content
echo "<br />Now, we try to modify the notice's content." . '<br />' . '<br />';
$notice->content = 'The behavior is safty but you should be careful still.';
<?php
namespace Common\Observer;
interface Observer
{
/**
* @param \Common\Observer\Subject $subject
*/
function update($subject);
}
<?php
namespace Common\Observer;
use SplObjectStorage;
/**
* The subject implement in the observer pattern.
*
* @author TonySeek
*
*/
trait Subject
{
private $observers = null;
/**
* Create or get existed observer object container.
*
* @return \SplObjectStorage;
*/
private function getObserverStorage()
{
if (!$this->observers) {
$this->observers = new SplObjectStorage();
}
return $this->observers;
}
/**
* @return \Common\Observer\Subject
*/
public function attachObserver(Observer $observer)
{
$storage = $this->getObserverStorage();
$storage->attach($observer);
return $this;
}
/**
* @return \Common\Observer\Subject
*/
public function detachObserver(Observer $observer)
{
$storage = $this->getObserverStorage();
$storage->detach($observer);
return $this;
}
/**
* @see SplSubject::notify()
*/
public function notify()
{
$storage = $this->getObserverStorage();
foreach($storage as $observer) {
$observer->update($this);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment