PHP Conference Japan 2024

SplSubject 介面

(PHP 5 >= 5.1.0, PHP 7, PHP 8)

簡介

SplSubject 介面與 SplObserver 一起使用,以實作觀察者設計模式。

介面概要

interface SplSubject {
/* 方法 */
public attach(SplObserver $observer): void
public detach(SplObserver $observer): void
public notify(): void
}

目錄

新增筆記

使用者貢獻的筆記 4 筆筆記

23
przemyslaw dot szpiler at gmail dot com
12 年前
<?php

// 觀察者設計模式的範例實作:

class MyObserver1 implements SplObserver {
public function
update(SplSubject $subject) {
echo
__CLASS__ . ' - ' . $subject->getName();
}
}

class
MyObserver2 implements SplObserver {
public function
update(SplSubject $subject) {
echo
__CLASS__ . ' - ' . $subject->getName();
}
}

class
MySubject implements SplSubject {
private
$_observers;
private
$_name;

public function
__construct($name) {
$this->_observers = new SplObjectStorage();
$this->_name = $name;
}

public function
attach(SplObserver $observer) {
$this->_observers->attach($observer);
}

public function
detach(SplObserver $observer) {
$this->_observers->detach($observer);
}

public function
notify() {
foreach (
$this->_observers as $observer) {
$observer->update($this);
}
}

public function
getName() {
return
$this->_name;
}
}

$observer1 = new MyObserver1();
$observer2 = new MyObserver2();

$subject = new MySubject("test");

$subject->attach($observer1);
$subject->attach($observer2);
$subject->notify();

/*
將會輸出:

MyObserver1 - test
MyObserver2 - test
*/

$subject->detach($observer2);
$subject->notify();

/*
將會輸出:

MyObserver1 - test
*/

?>
2
xedin dot unknown at gmail dot com
5 年前
幾年來,我嘗試了好幾次想了解 Subject/Observer 配對背後的架構。最近我又試了一次。我就是無法想像為什麼有人會以文件記載的方式來設計它。我的意思是,「他們在想什麼?!」,我心想。如果 Subject 外部的東西可以告訴它何時通知觀察者,那將會完全破壞封裝。因為只有 subject 可以知道內部事件何時發生。因此,暴露 `notify()` 將會嚴重違反許多良好的 OOP 設計原則。

不過,我想出一個這種方式是有效的場景。也就是說,如果 Subject 代表一個 Hook,就像在 WordPress 中一樣。例如,在事件系統中,事件是以名稱或程式碼調用的,Hook 可以代表系統中的一個命名事件,並且透過從外部呼叫 `notify()`,調度器可以通知觀察者。如果這是預期的情境,那麼問題主要在於命名:「Subject」這個名稱暗示它是被觀察的對象,而觀察者模式是不同的。
3
匿名
11 年前
<?php
class Observable implements SplSubject
{
private
$storage;

function
__construct()
{
$this->storage = new SplObjectStorage();
}

function
attach(SplObserver $observer)
{
$this->storage->attach($observer);
}

function
detach(SplObserver $observer)
{
$this->storage->detach($observer);
}

function
notify()
{
foreach (
$this->storage as $obj) {
$obj->update($this);
}
}
//...
}

abstract class
Observer implements SplObserver
{
private
$observable;

function
__construct(Observable $observable)
{
$this->observable = $observable;
$observable->attach($this);
}

function
update(SplSubject $subject)
{
if (
$subject === $this->observable) {
$this->doUpdate($subject);
}
}

abstract function
doUpdate(Observable $observable);
}

class
ConcreteObserver extends Observer
{
function
doUpdate(Observable $observable)
{
//...
}
}

$observable = new Observable();
new
ConcreteObserver($observable);
2
aiddroid at example dot com
11 年前
/**
* 主題,發布消息者
*/
class Newspaper implements \SplSubject{
private $name;
private $observers = array();
private $content;

public function __construct($name) {
$this->name = $name;
}

//新增觀察者
public function attach(\SplObserver $observer) {
$this->observers[] = $observer;
}

//移除觀察者
public function detach(\SplObserver $observer) {

$key = array_search($observer,$this->observers, true);
if($key){
unset($this->observers[$key]);
}
}

//設定突發新聞
public function breakOutNews($content) {
$this->content = $content;
$this->notify();
}

public function getContent() {
return $this->content." (by {$this->name})";
}

//通知觀察者(或部分觀察者)
public function notify() {
foreach ($this->observers as $value) {
$value->update($this);
}
}
}

/**
* 觀察者,接收消息者
*/
class Reader implements SplObserver{
private $name;

public function __construct($name) {
$this->name = $name;
}

public function update(\SplSubject $subject) {
echo $this->name.' 正在閱讀突發新聞 <b>'.$subject->getContent().'</b><br>';
}
}

//類別測試
$newspaper = new Newspaper('紐約時報');

$allen = new Reader('艾倫');
$jim = new Reader('吉姆');
$linda = new Reader('琳達');

//新增讀者
$newspaper->attach($allen);
$newspaper->attach($jim);
$newspaper->attach($linda);

//移除讀者
$newspaper->detach($linda);

//設定突發新聞
$newspaper->breakOutNews('美國崩潰了!');

//=========輸出==========
//艾倫 正在閱讀突發新聞 USA break down! (by 紐約時報)
//吉姆 正在閱讀突發新聞 USA break down! (by 紐約時報)
To Top