The Standard PHP Library includes what some resources call a reference implementation of the Observer pattern, by way of the SplSubject
and SplObserver
classes. For the life of me, I can't figure out how these are very useful with no way to pass actual events or any other information along with the notifications:
class MySubject implements SplSubject {
protected $_observers = [];
public function attach(SplObserver $observer) {
$id = spl_object_hash($observer);
$this->_observers[$id] = $observer;
}
public function detach(SplObserver $observer) {
$id = spl_object_hash($observer);
if (isset($this->_observers[$id])) {
unset($this->_observers[$id]);
}
}
public function notify() {
foreach ($this->_observers as $observer) {
$observer->update($this);
}
}
}
class MyObserver implements SplObserver {
public function update(SplSubject $subject) {
// something happened with $subject, but what
// was it???
}
}
$subject = new MySubject();
$observer = new MyObserver();
$subject->attach($observer);
$subject->notify();
It seems like these interfaces are pretty much useless for any real world problem. Can someone enlighten me?
Edit:
Here's my biggest problem with the interface (although there are others):
public function update(SplSubject $subject, Event $event) { /* ... */ }
...nets the following fatal error:
PHP Fatal error: Declaration of MyObserver::update() must be compatible with SplObserver::update(SplSubject $SplSubject)
Edit #2:
Making the additional parameters optional by giving them defaults prevents the fatal error and provides a way to pass context, making implementations worthwhile. I wasn't previously aware of this, so this pretty much answers my question. The solution is to pass your own event/message data, and check for its existance inside SplObserver::update()
.
It seems like these interfaces are pretty much useless for any real world problem. Can someone enlighten me?
Interface
While abstract classes let you provide some measure of implementation, interfaces are pure templates. An interface
can only define functionality
; it can never implement it. An interface is declared with the interface keyword. It can contain properties and method declarations, but not method bodies.
Interface Use case
For example if you want to your project should support different databases . so that you can change your database in future its better to use interfaces that contains property procedures in class file with out altering objects
By itself, interfaces are not very useful
because You cannot create instances of interfaces but Interfaces are instrumental in enforcing object oriented design methodologies which in real sense makes your live easier as a programmer
because the foremost incentive for object oriented programming is encapsulation (You don't care how a capability is implemented. You, as a programmer, are exposed only to the interface. This is also a good way to watch after the system architecture)
SplSubject & SplObserver
Orthogonality is a virtue , One of objectives as programmers should be to build components that can be altered or moved with minimal impact on other components.
If every change you make to one component necessitates a ripple of changes elsewhere in the codebase, the task of development can quickly become a spiral of bug creation and elimination.
There is no special feature of SplSubject and SplObserver because thy are both interface to implement the Observer Design Pattern.
Observer pattern
The observer pattern is a software design pattern in which an object, called the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods. It is mainly used to implement distributed event handling systems
Example 1. Interest Rate Notification System for a Loan
$loan = new Loan("Mortage", "Citi Bank", 20.5);
$loan->attach(new Online());
$loan->attach(new SMS());
$loan->attach(new Email());
echo "<pre>";
$loan->setIntrest(17.5);
Output
Online : Post online about modified Intrest rate of : 17.50
Send SMS : Send SMS to premium subscribers : 17.50
Send Email: Notify mailing list : 17.50
Example 2. Simple User Register Monitor
$users = new Users();
new Audit($users);
new Logger($users);
new Security($users);
$users->addUser("John");
$users->addUser("Smith");
$users->addUser("Admin");
Output
Audit : Notify Audit about John
Log : User John Create at Wed, 12 Dec 12 12:36:46 +0100
Audit : Notify Audit about Smith
Log : User Smith Create at Wed, 12 Dec 12 12:36:46 +0100
Audit : Notify Audit about Admin
Log : User Admin Create at Wed, 12 Dec 12 12:36:46 +0100
Security : Alert trying to create Admin
Advantage of Observer Design Pattern: Main advantage is loose coupling between objects called observer and observable. The subject only know the list of observers it don’t care about how they have their implementation.All the observers are notified by subject in a single event call as Broadcast communication
Disadvantage of Observer Design Pattern:
Common Classes
abstract class Observable implements SplSubject {
protected $_observers = [];
public function attach(SplObserver $observer) {
$id = spl_object_hash($observer);
$this->_observers[$id] = $observer;
}
public function detach(SplObserver $observer) {
$id = spl_object_hash($observer);
if (isset($this->_observers[$id])) {
unset($this->_observers[$id]);
}
}
public function notify() {
foreach ( $this->_observers as $observer ) {
$observer->update($this);
}
}
}
abstract class Observer implements SplObserver {
private $observer;
function __construct(SplSubject $observer) {
$this->observer = $observer;
$this->observer->attach($this);
}
}
Load Example Classes
class Loan extends Observable {
private $bank;
private $intrest;
private $name;
function __construct($name, $bank, $intrest) {
$this->name = $name;
$this->bank = $bank;
$this->intrest = $intrest;
}
function setIntrest($intrest) {
$this->intrest = $intrest;
$this->notify();
}
function getIntrest() {
return $this->intrest;
}
}
class Online implements SplObserver {
public function update(SplSubject $loan) {
printf("Online : Post online about modified Intrest rate of : %0.2f\n",$loan->getIntrest());
}
}
class SMS implements SplObserver {
public function update(SplSubject $loan) {
printf("Send SMS : Send SMS to premium subscribers : %0.2f\n",$loan->getIntrest());
}
}
class Email implements SplObserver {
public function update(SplSubject $loan) {
printf("Send Email: Notify mailing list : %0.2f\n",$loan->getIntrest());
}
}
User Register Example Classes
class Users extends Observable {
private $name;
function addUser($name) {
$this->name = $name;
$this->notify();
}
function getName() {
return $this->name;
}
}
class Audit extends Observer {
public function update(SplSubject $subject) {
printf("Audit : Notify Autify about %s\n", $subject->getName());
}
}
class Logger extends Observer {
public function update(SplSubject $subject) {
printf("Log : User %s Create at %s\n", $subject->getName(),date(DATE_RFC822));
}
}
class Security extends Observer {
public function update(SplSubject $subject) {
if($subject->getName() == "Admin")
{
printf("Security : Alert trying to create Admin\n");
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With