<?php

/* This is a sample of Observer design pattern for PHP5.
*
* $Id: observer.php,v 1.1 2004/02/12 15:28:59 tea Exp tea $
*/

function array_remove(&$array, $element) {
    
array_splice($array, array_search($element, $array), 1);
}

class
DoubleAttachException
{
    function
__construct(Observer $observer) {
        
$this->observer = $observer;
    }
    
    public function
getException() {
        return
"(" . $this->observer . ") is registered already.\n";
    }
}

interface
Observer
{
    abstract function
update();
}

abstract class
Subject
{
    function
__construct() {
        
$this->observers = array();
    }

    public function
attach(Observer $observer) {
        if (
in_array($observer, $this->observers)) {
            throw new
DoubleAttachException($observer);
        }
        else {
            
$this->observers[] = $observer;
        }
    }
    
    public function
detach(Observer $observer) {
        if (
in_array($observer, $this->observers)) {
            
array_remove($this->observers, $observer);
        }
    }
    
    protected function
notifyAll() {
        foreach (
$this->observers as $observer) {
            
$observer->update($this);
        }
    }
}

class
Point implements Observer
{
    function
__construct($name) {
        
$this->name = $name;
    }

    public function
update() {
        print
"Point($this->name)\n";
    }
}

class
Screen extends Subject
{
    function
__construct($x, $y, $color) {
        
parent::__construct();
        
$this->x = $x;
        
$this->y = $y;
        
$this->color = $color;
    }
    
    public function
setX($x) {
        
$this->x = $x;
        
$this->notifyAll();
    }

    public function
setY($y) {
        
$this->y = $y;
        
$this->notifyAll();
    }

    public function
setColor($color) {
        
$this->color = $color;
        
$this->notifyAll();
    }
}

try {
    
$screen = new Screen(10, 20, "red");
    
$screen->attach($p1 = new Point("A"));
    
$screen->attach($p2 = new Point("B"));
    
$screen->attach($p3 = new Point("C"));

    
# Attach the same observer again.
    # This will throw DoubleAttachException.
    # $screen->attach($p1);

    
print "screen set X = 10\n";
    
$screen->setX(10);

    print
"now detach p2 object\n";
    
$screen->detach($p2);

    print
"screen set color = blue\n";
    
$screen->setColor("blue");
}
catch (
DoubleAttachException $exception) {
    print
$exception->getException();
}

?>