<?php 
/* 
 * 观察者模式 
 * 观察者模式有两个对象,一个为subject(主题),一个为observer(观察者) 
 * 观察者模式两个对象为低耦合状态,相互关联又不相互依赖。你中有我,我中有你 
 * 观察者模式中,针对subject,应具有添加、删除观察者的方法,还应该具有对观察者进行消息提醒的模式 
 * 按照java中的方法,增加了一个change变量,属于是否进行notify的flag 
 * 主题主动进行notify发送,会调用observer的update方法,并传入自己,便于observer针对不同的主题进行不同的操作 
 */ 

class Subject implements SplSubject { 

    private $observers = array(); //存储所有observers 
    private $changed = FALSE; //是否发送notify 

    public function attach(SplObserver $observer) { 
        //添加observer 
        $this->observers[] = $observer;
    }

    public function detach(SplObserver $observer) { 
        //删除observer
        $position = array_search($observer, $this->observers);

        if ($position !== FALSE) {
            unset($this->observers[$position]);
        }
    }

    public function notify() { 
        //进行通知
        foreach($this->observers as $observer) {
            $observer->update($this); 
            //调用observer的update方法,进行notify发送
        }

        $this->changed = FALSE;
    }

    public function setChange() { 
        //设定可进行notify发送
        $this->changed = TRUE;
    }
}

class Observer implements SplObserver {

    public function update(SplSubject $subject) {
    }
}

class RSS extends Subject {
}

class NEWS extends Subject {
}

class User extends Observer {

    public function __construct() {
        foreach(func_get_args() as $arg) {
            if ($arg instanceof SplSubject) {
                $arg->attach($this); //初始化时,绑定主题
            }
        }
    }

    public function update(SplSubject $subject) { //主题会主动调用改方法
        switch(get_class($subject)) {
            case 'RSS' : $this->read_rss();
                break;
            case 'NEWS' : $this->read_news();
                break;
            default :
            break;
        }
    }

    private function read_rss() {
        echo 'Observer Read_RSS'; 
    }

    private function read_news() {
        echo 'Observer Read_News'; 
    }
}

//生成两个主题
$rss = new RSS();
$news = new NEWS();

//生成一个观察者,观察了两个主题
$user = new User($rss, $news);

//设定news可进行notify
$news->setChange();
//执行notify
$news->notify(); //显示Observer Read_News
echo "n";

//设定ress可进行notify
$rss->setChange();
//执行notify
$rss->notify(); //显示Observer Read_RSS
echo "n";

//作为主题,对user进行detach
$rss->detach($user);

//rss进行notify发送
$rss->setChange();
$rss->notify(); //页面无显示