·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> php网站开发 >> PHP 高级编程(3/5)

PHP 高级编程(3/5)

作者:佚名      php网站开发编辑:admin      更新时间:2022-07-23
php 高级编程(3/5) - 使用SPL(标准PHP库)实现观察者模式

SPL(标准PHP库 - Standard PHP Library)是PHP5面向对象功能中重要的部分。原文解释是这样的“The Standard PHP Library (SPL) is a collection of interfaces and classes that are meant to solve common PRoblems”。

SplSubject 和 SplObserver 接口

The SplSubject interface is used alongside SplObserver to implement the Observer Design Pattern.

观察者模式是一种简单的事件系统,包含了两个或更多的互相交互的类。这一模式允许某个类观察另一个类的状态,当被观察类的状态发生变化时,这个模式会得到通知。被观察的类叫subject,负责观察的类叫做Observer 。PHP 提供的 SplSubject 和 SplObserver接口可用来表达这些内容。

SplSubject {/* 方法 */abstract public void attach ( SplObserver $observer )abstract public void detach ( SplObserver $observer )abstract public void notify ( void )}
SplObserver {/* 方法 */abstract public void update ( SplSubject $subject )}

这里,splsubject类维护了一个特定状态,当这个状态发生变化时,他就会调用notify方法,所以之前使用attach注册的splobserver实例的update就会被调用。这里我们实现一个简单地观察者模式的例子

<?php/** * Subject,that who makes news */class Newspaper implements \SplSubject{    private $name;    private $observers = array();    private $content;        public function __construct($name) {        $this->name = $name;    }    //add observer    public function attach(\SplObserver $observer) {        $this->observers[] = $observer;    }        //remove observer    public function detach(\SplObserver $observer) {                $key = array_search($observer,$this->observers, true);        if($key){            unset($this->observers[$key]);        }    }        //set breakouts news    public function breakOutNews($content) {        $this->content = $content;        $this->notify();    }        public function getContent() {        return $this->content." ({$this->name})";    }        //notify observers(or some of them)    public function notify() {        foreach ($this->observers as $value) {            $value->update($this);        }    }}/** * Observer,that who recieves news */class Reader implements SplObserver{    private $name;        public function __construct($name) {        $this->name = $name;    }        public function update(\SplSubject $subject) {        echo $this->name.' is reading breakout news <b>'.$subject->getContent().'</b><br>';    }}$newspaper = new Newspaper('Newyork Times');$allen = new Reader('Allen');$jim = new Reader('Jim');$linda = new Reader('Linda');//add reader$newspaper->attach($allen);$newspaper->attach($jim);$newspaper->attach($linda);//remove reader$newspaper->detach($linda);//set break outs$newspaper->breakOutNews('USA break down!');//=====output======//Allen is reading breakout news USA break down! (Newyork Times)//Jim is reading breakout news USA break down! (Newyork Times)

上例中我们通过数组存储 observer对象,使用数组及可能会出现两个问题:

1、同一个observer可能会被加载多次,导致多次调用同一个对象的update方法。

2、detach中需要通过迭代或者搜索数组来找到要删除的observer对象,导致运行效率降低。

SplObjectStorage类

PHP5提供了SplObjectStorage类,在这里我们可以用来存储observer对象,SplObjectStoraged的实例就像一个数组,但是他所存放的对象是唯一的。SplObjectStorage还可以使用detach直接从集合中删除指定的对象而不用遍历或搜索整个集合。下面看一个SplObjectStorage的例子:

<?php $ObjectStorage = new SplObjectStorage(); class classa {     #code... } class classb {    #code... }$a = new classa();$b = new classb();$ObjectStorage->attach($a);$ObjectStorage->attach($b);$ObjectStorage->attach($a);foreach ($ObjectStorage as $key => $item) {    echo ($key+1).'、'.(new ReflectionClass($item))->getName()."\n";}//output

1、classa 2、classb [Finished in 0.1s]

?>

上例中我们可以看到,在ObjectStorage这个集合中只有1个calssa,尽管我们添加了两次。并且冲集合中删除一个元素也变得极为简单,拿上面的代码来说,只需使用$ObjectStorage->attach($a);即可轻松的将$a从集合中移除。

结合 SplObjectStorage 我们再来修改最上面那个观察者模式的例子

<?php/** * Subject,that who makes news */class Newspaper implements \SplSubject{    private $name;    private $observers;    private $content;        public function __construct($name) {        $this->name = $name;        $this->observers = new SplObjectStorage();    }    //add observer    public function attach(\SplObserver $observer) {        $this->observers -> attach($observer);    }        //remove observer    public function detach(\SplObserver $observer) {        $this->observers -> detach($observer);    }        //set breakouts news    public function breakOutNews($content) {        $this->content = $content;        $this->notify();    }        public function getContent() {        return $this->content." ({$this->name})";    }        //notify observers(or some of them)    public function notify() {        foreach ($this->observers as $value) {            $value->update($this);        }    }}/** * Observer,that who recieves news */class Reader implements SplObserver{    private $name;        public function __construct($name) {        $this->name = $name;    }        public function update(\SplSubject $subject) {        echo $this->name.' is reading breakout news '.$subject->getContent()."\n";    }}$newspaper = new Newspaper('Newyork Times');$allen = new Reader('Allen');$jim = new Reader('Jim');$linda = new Reader('Linda');//add reader$newspaper->attach($allen);$newspaper->attach($jim);$newspaper->attach($linda);//remove reader$newspaper->detach($linda);//set break outs$newspaper->breakOutNews('USA break down!');//=====output======//Allen is reading breakout news USA break down! (Newyork Times)//Jim is reading breakout news USA break down! (Newyork Times)