<?php
/**
 * 观察者模式, 完成用户登录
 * php5中提供 被观察者subject 与 观察者observer 的接口
 * 
 * @author hhcycj
 *
 */

/**
 * 被观察者
 * @author hhcyc
 *
 */
class user implements SplSubject{
    public $lognum;
    public $hobby;

    protected $observers = null;

    public function __construct($hobby){
        $this->lognum = rand(1, 10);
        $this->hobby  = $hobby;

        // 存储多个观察者
        $this->observers = new SplObjectStorage();
    }

    public function login(){
        /**
         * 这里可以做登录操作,然后再调用notify函数 通知 观察者(observer)
         */
        $this->notify();
    }


    /**
     * Attach an SplObserver
     * @param observer SplObserver <p>
     * The SplObserver to attach.
     * </p>
     * @return void
     */
    public function attach (SplObserver $observer) {
        /**
         * 将观察者类,存储到被observers
         */
        $this->observers->attach($observer);
    }

    /**
     * Detach an observer
     * @param observer SplObserver <p>
     * The SplObserver to detach.
     * </p>
     * @return void
     */
    public function detach (SplObserver $observer) {
        /**
         * 删除在observers中的观察者
         */
        $this->observers->detach($observer);
    }

    /**
     * Notify an observer
     * @return void
     */
    public function notify () {

        /**
         * Rewind the iterator to the first storage element
         * @return void
         */
        $this->observers->rewind();

        /**
         * Returns if the current iterator entry is valid
         * @return bool true if the iterator entry is valid, false otherwise.
         */
        while ($this->observers->valid()){

            /**
             * Returns the current storage entry
             * @return object The object at the current iterator position.
             */
            $observer = $this->observers->current();

            /**
             * 根据返回的观察者(observer),调用他们本身的update函数
             */
            $observer->update($this);
            $this->observers->next();
        }
    }
}

/**
 * 安全登录模块(观察者)
 * @author hhcyc
 *
 */
class secrity implements SplObserver{
    /**
     * Receive update from subject
     * @param subject SplSubject <p>
     * The SplSubject notifying the observer of an update.
     * </p>
     * @return void
     */
    public function update (SplSubject $subject) {
        if ($subject->lognum < 3) {
            echo '这是第'.$subject->lognum.'次安全登录<br />';
        }else{
            echo '这是第'.$subject->lognum.'次登录,异常<br />';
        }
    }
}

/**
 * 广告模块(观察者)
 * @author hhcyc
 *
 */
class ad implements SplObserver{
    /**
     * Receive update from subject
     * @param subject SplSubject <p>
     * The SplSubject notifying the observer of an update.
     * @return void
     */
    public function update (SplSubject $subject) {
        if ($subject->hobby == 'sports') {
            echo '台球英锦赛门票预定<br />';
        }else{
            echo '好好学习,天天向上<br />';
        }
    }
}


/**
 * 实施观察
 */
$user = new user('sports');
$user->attach(new secrity());
$user->attach(new ad());
$user->login();