Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【PHP8.x】SplObserver::update()メソッドの使い方

updateメソッドの使い方について、初心者にもわかりやすく解説します。

作成日: 更新日:

基本的な使い方

updateメソッドは、PHPのSplObserverインターフェースを実装するクラスで定義されるメソッドです。このメソッドは、「オブザーバーパターン」と呼ばれるデザインパターンにおいて、監視対象となるオブジェクト(これを「Subject」と呼び、SplSubjectインターフェースを実装します)の状態が変化した際に、その変化を通知された監視側(「Observer」と呼び、SplObserverインターフェースを実装します)が実行すべき具体的な処理を定義するために使用されます。

updateメソッドが呼び出されると、引数として状態が変化したSplSubjectオブジェクト自身を受け取ります。これにより、オブザーバーはSubjectの現在の状態を問い合わせたり、その情報に基づいて自身の状態を更新したり、あるいは関連する他の操作を実行したりすることができます。

例えば、あるシステムでデータベースのデータが更新されたとき、このupdateメソッドを使って、そのデータ表示画面の再描画、ログへの記録、関連するキャッシュのクリアなど、複数の処理を自動的に連動させて実行することが可能です。この仕組みにより、SubjectとObserverの間で直接的な依存関係を低減させ、それぞれのオブジェクトの役割を明確に分離することで、システムの柔軟性と保守性を向上させる設計を実現します。

構文(syntax)

1<?php
2
3interface SplObserver
4{
5    public function update(SplSubject $subject): void;
6}

引数(parameters)

SplSubject $subject

  • SplSubject $subject: 自身を通知した SplSubject オブジェクト

戻り値(return)

戻り値なし

戻り値はありません

サンプルコード

PHP SplObserver update メソッドでSQL UPDATEする

1<?php
2
3/**
4 * Subjectインターフェースを実装するクラスの例。
5 * 複数のオブザーバーに自身の状態変更を通知する責任を持ちます。
6 * この例では、商品情報を保持するSubjectとして機能します。
7 */
8class ProductSubject implements SplSubject
9{
10    /** @var SplObserver[] 登録されているオブザーバーのリスト */
11    private array $observers = [];
12
13    /** @var int 商品ID */
14    public int $id;
15
16    /** @var string 商品名 */
17    public string $name;
18
19    /** @var float 商品価格 */
20    public float $price;
21
22    public function __construct(int $id, string $name, float $price)
23    {
24        $this->id = $id;
25        $this->name = $name;
26        $this->price = $price;
27    }
28
29    /**
30     * オブザーバーをアタッチ(登録)します。
31     *
32     * @param SplObserver $observer 登録するオブザーバーオブジェクト
33     */
34    public function attach(SplObserver $observer): void
35    {
36        $this->observers[spl_object_hash($observer)] = $observer;
37        echo "LOG: Observer attached to ProductSubject #{$this->id}.\n";
38    }
39
40    /**
41     * オブザーバーをデタッチ(登録解除)します。
42     *
43     * @param SplObserver $observer 登録解除するオブザーバーオブジェクト
44     */
45    public function detach(SplObserver $observer): void
46    {
47        unset($this->observers[spl_object_hash($observer)]);
48        echo "LOG: Observer detached from ProductSubject #{$this->id}.\n";
49    }
50
51    /**
52     * 登録されている全てのオブザーバーに状態変更を通知します。
53     */
54    public function notify(): void
55    {
56        echo "LOG: ProductSubject #{$this->id} is notifying observers...\n";
57        foreach ($this->observers as $observer) {
58            $observer->update($this); // 各オブザーバーのupdateメソッドを呼び出す
59        }
60    }
61
62    /**
63     * 商品の価格を変更し、その後オブザーバーに通知します。
64     *
65     * @param float $newPrice 新しい価格
66     */
67    public function setPrice(float $newPrice): void
68    {
69        if ($this->price !== $newPrice) {
70            $oldPrice = $this->price;
71            $this->price = $newPrice;
72            echo "ACTION: Product #{$this->id} price changed from {$oldPrice} to {$this->price}.\n";
73            $this->notify(); // 価格変更後にオブザーバーへ通知
74        } else {
75            echo "INFO: Product #{$this->id} price is already {$this->price}. No change, no notification.\n";
76        }
77    }
78}
79
80/**
81 * Observerインターフェースを実装するクラスの例。
82 * Subjectからの通知を受け取り、それに応じてアクションを実行します。
83 * この例では、受け取ったSubjectの状態に基づいてデータベースのUPDATE操作をシミュレートします。
84 */
85class DatabaseUpdateObserver implements SplObserver
86{
87    /**
88     * Subjectからの更新通知を受け取ります。
89     * このメソッド内で、データベースのUPDATE処理などの具体的なアクションを実行します。
90     *
91     * @param SplSubject $subject 通知元のSubjectオブジェクト
92     */
93    public function update(SplSubject $subject): void
94    {
95        // 受け取ったSubjectが期待する型(ProductSubject)であることを確認
96        if ($subject instanceof ProductSubject) {
97            // Subjectオブジェクトから最新のデータを取得し、SQL UPDATE文をシミュレートします。
98            // 実際のアプリケーションでは、PDOなどのデータベースライブラリを使用して
99            // プリペアドステートメントで安全にデータを更新します。
100            $simulatedSql = sprintf(
101                "UPDATE products SET name = '%s', price = %.2f WHERE id = %d;",
102                addslashes($subject->name), // SQLインジェクション対策は実際のDB操作では必須
103                $subject->price,
104                $subject->id
105            );
106
107            echo "OBSERVER ACTION: DatabaseUpdateObserver received update for Product #{$subject->id}.\n";
108            echo "  Simulating SQL UPDATE: {$simulatedSql}\n";
109        } else {
110            echo "OBSERVER INFO: DatabaseUpdateObserver received update from an unsupported subject type.\n";
111        }
112    }
113}
114
115// --------------------------------------------------------------------------
116// サンプルコード実行部分
117// --------------------------------------------------------------------------
118
119// 1. 監視対象となるSubject(商品)を作成します。
120$product = new ProductSubject(101, 'Sample Widget', 99.99);
121
122// 2. Subjectの状態変化を監視するObserver(データベース更新担当)を作成します。
123$dbObserver = new DatabaseUpdateObserver();
124
125// 3. ObserverをSubjectにアタッチ(登録)します。
126// これにより、Subjectの状態が変化した際にObserverが通知を受け取れるようになります。
127$product->attach($dbObserver);
128
129echo "\n--- 最初の価格変更 ---\n";
130// 4. Subject(商品)の価格を変更します。
131// setPrice()メソッド内でnotify()が呼ばれ、Observerのupdate()メソッドが実行されます。
132$product->setPrice(105.50);
133
134echo "\n--- 2回目の価格変更 ---\n";
135$product->setPrice(110.00);
136
137echo "\n--- 同じ価格への設定(変更なし) ---\n";
138// 価格に変化がない場合、notify()は呼ばれないためObserverも通知を受け取りません。
139$product->setPrice(110.00);
140
141echo "\n--- オブザーバーをデタッチ ---\n";
142// 必要に応じてObserverをSubjectからデタッチ(登録解除)できます。
143$product->detach($dbObserver);
144
145echo "\n--- デタッチ後の価格変更(通知されない) ---\n";
146// Observerがデタッチされたため、setPrice()を呼び出してもObserverは通知を受け取りません。
147$product->setPrice(120.00);
148
149?>

PHPのSplObserver::updateメソッドは、Observerデザインパターンにおいて、監視される側であるSubjectオブジェクトからの状態変更通知を受け取るための重要なメソッドです。このメソッドは、SplSubjectインターフェースを実装したオブジェクトが状態を変化させた際に、その変更を監視している全てのSplObserverオブジェクトに対して自動的に呼び出されます。

引数SplSubject $subjectは、どのSubjectオブジェクトが状態を変更し、通知を発したのかを示します。Observerはこの引数を通じて、通知元のSubjectの現在の状態や変更された情報を取得し、それに応じた具体的な処理を実行できます。このメソッドの戻り値はvoidであり、Observerは通知を受け取った後、値を返す必要はありません。

サンプルコードでは、ProductSubjectクラスが商品の価格変更を検知すると、登録されているDatabaseUpdateObserverクラスのupdateメソッドを呼び出します。DatabaseUpdateObserver::updateメソッドは、引数として受け取ったProductSubjectオブジェクトから最新の商品ID、名前、価格を取得し、それらを用いてデータベースのUPDATE文をシミュレートする処理を実行しています。これにより、商品の価格が変更されるたびに、関連するデータベースのレコードも自動的に更新される、という一連の流れが実現されます。これは、アプリケーションの状態変化とデータベースの同期処理を効率的に連携させる一般的な方法の一つです。

SplObserver::updateメソッドは、監視対象のオブジェクト(Subject)から状態変化の通知を受け取るための機能です。引数には通知元のSubjectオブジェクトが渡され、戻り値はありません。このサンプルコードでは、受け取ったSubjectの状態に基づいてデータベースのUPDATE操作をシミュレートしていますが、実際のシステムではSQLインジェクションを防ぐため、addslashesのような関数ではなく、PDOなどのデータベースライブラリを用いたプリペアドステートメントを必ず利用してください。また、複数の異なるSubjectを監視する場合、updateメソッド内で通知元のSubjectの型を確認し、適切な処理を行うことが重要です。

PHP SplObserver updateメソッドによる通知処理

1<?php
2
3declare(strict_types=1);
4
5/**
6 * SplSubjectインターフェースを実装する具体的な「主題」クラス。
7 * 複数のオブザーバーに自身の状態変更を通知する役割を持ちます。
8 */
9class WeatherData implements SplSubject
10{
11    /** @var SplObserver[] 登録されているオブザーバーのリスト */
12    private array $observers = [];
13    private float $temperature;
14    private float $humidity;
15    private float $pressure;
16
17    public function __construct(float $temperature = 0.0, float $humidity = 0.0, float $pressure = 0.0)
18    {
19        $this->temperature = $temperature;
20        $this->humidity = $humidity;
21        $this->pressure = $pressure;
22    }
23
24    /**
25     * オブザーバーを登録します。
26     * 登録されたオブザーバーは、主題の状態変更時に通知を受け取ります。
27     */
28    public function attach(SplObserver $observer): void
29    {
30        $this->observers[spl_object_hash($observer)] = $observer;
31        echo "通知を監視するオブザーバーが登録されました: " . get_class($observer) . "\n";
32    }
33
34    /**
35     * オブザーバーの登録を解除します。
36     * 解除されたオブザーバーは、主題からの通知を受け取らなくなります。
37     */
38    public function detach(SplObserver $observer): void
39    {
40        unset($this->observers[spl_object_hash($observer)]);
41        echo "通知を監視するオブザーバーが解除されました: " . get_class($observer) . "\n";
42    }
43
44    /**
45     * 登録されている全てのオブザーバーに状態変更を通知します。
46     * 各オブザーバーの`update()`メソッドが呼び出されます。
47     */
48    public function notify(): void
49    {
50        echo "オブザーバーに状態変更を通知します...\n";
51        foreach ($this->observers as $observer) {
52            // SplObserver::update() メソッドを呼び出し、自身のインスタンス ($this) を渡します。
53            $observer->update($this);
54        }
55    }
56
57    /**
58     * 気象データを設定し、変更があったことをオブザーバーに通知します。
59     * ここでの「update」は、主題のデータが更新されることを意味します。
60     */
61    public function setMeasurements(float $temperature, float $humidity, float $pressure): void
62    {
63        $this->temperature = $temperature;
64        $this->humidity = $humidity;
65        $this->pressure = $pressure;
66        echo "気象データが更新されました。オブザーバーに通知します。\n";
67        $this->notify(); // データ更新後にオブザーバーへ通知
68    }
69
70    // 現在の気象データを取得するゲッターメソッド群
71    public function getTemperature(): float
72    {
73        return $this->temperature;
74    }
75
76    public function getHumidity(): float
77    {
78        return $this->humidity;
79    }
80
81    public function getPressure(): float
82    {
83        return $this->pressure;
84    }
85}
86
87/**
88 * SplObserverインターフェースを実装する具体的な「オブザーバー」クラス。
89 * 主題から通知を受け取り、自身の状態を更新したり、何らかの処理を実行します。
90 */
91class CurrentConditionsDisplay implements SplObserver
92{
93    private float $temperature;
94    private float $humidity;
95
96    public function __construct(SplSubject $weatherData)
97    {
98        // オブザーバーが作成された際に、自動的に主題に登録します。
99        $weatherData->attach($this);
100    }
101
102    /**
103     * 主題から更新通知を受け取るメソッド。
104     * このメソッドは、主題の`notify()`メソッドによって呼び出されます。
105     *
106     * @param SplSubject $subject 通知を送ってきた主題のインスタンス
107     * ここで主題の状態を問い合わせ、表示内容などを更新します。
108     * この「update」は、オブザーバーが主題の更新情報を受け取ることを意味します。
109     */
110    public function update(SplSubject $subject): void
111    {
112        // instanceofで、期待するSubject型からの通知であることを確認することが推奨されます。
113        if ($subject instanceof WeatherData) {
114            $this->temperature = $subject->getTemperature();
115            $this->humidity = $subject->getHumidity();
116            $this->display(); // 受け取った情報をもとに表示を更新
117        } else {
118            // 予期しない主題型からの通知の場合の処理 (ログ記録など)
119            error_log("予期しない主題型からの通知: " . get_class($subject));
120        }
121    }
122
123    /**
124     * 現在の気象状態を表示するメソッド。
125     */
126    public function display(): void
127    {
128        echo "現在の気象状況: " . $this->temperature . "℃、湿度 " . $this->humidity . "%\n";
129    }
130}
131
132/**
133 * もう一つのオブザーバークラス。統計情報を表示します。
134 */
135class StatisticsDisplay implements SplObserver
136{
137    private float $maxTemp = 0.0;
138    private float $minTemp = 200.0; // ありえない低い値で初期化
139    private float $tempSum = 0.0;
140    private int $numReadings = 0;
141
142    public function __construct(SplSubject $weatherData)
143    {
144        $weatherData->attach($this);
145    }
146
147    /**
148     * 主題から更新通知を受け取り、統計情報を更新して表示します。
149     */
150    public function update(SplSubject $subject): void
151    {
152        if ($subject instanceof WeatherData) {
153            $temp = $subject->getTemperature();
154            $this->tempSum += $temp;
155            $this->numReadings++;
156
157            if ($temp > $this->maxTemp) {
158                $this->maxTemp = $temp;
159            }
160
161            if ($temp < $this->minTemp) {
162                $this->minTemp = $temp;
163            }
164            $this->display(); // 統計情報を更新して表示
165        }
166    }
167
168    /**
169     * 統計情報を表示するメソッド。
170     */
171    public function display(): void
172    {
173        if ($this->numReadings > 0) {
174            echo "気温 (平均/最高/最低): " . round($this->tempSum / $this->numReadings, 1) . "℃/" . $this->maxTemp . "℃/" . $this->minTemp . "℃\n";
175        } else {
176            echo "まだ気温の記録がありません。\n";
177        }
178    }
179}
180
181
182// --- メインの実行部分 ---
183echo "--- 気象観測所の初期化 ---\n";
184
185// 監視される「主題」(WeatherData) を作成します。
186$weatherData = new WeatherData();
187
188// 「オブザーバー」(表示器) を作成し、主題に登録します。
189// コンストラクタ内で attach() が呼び出されるため、ここで登録されます。
190$currentDisplay = new CurrentConditionsDisplay($weatherData);
191$statisticsDisplay = new StatisticsDisplay($weatherData);
192
193echo "\n--- 新しい気象データを設定 (1回目) ---\n";
194// WeatherDataの状態を更新します。
195// setMeasurements()内でnotify()が呼ばれ、全ての登録されたオブザーバーのupdate()が実行されます。
196$weatherData->setMeasurements(25.5, 65.0, 1013.2);
197
198echo "\n--- 新しい気象データを設定 (2回目) ---\n";
199$weatherData->setMeasurements(27.0, 70.0, 1012.0);
200
201echo "\n--- オブザーバーを解除します ---\n";
202// 統計表示オブザーバーの登録を解除します。
203$weatherData->detach($statisticsDisplay);
204
205echo "\n--- 新しい気象データを設定 (3回目) ---\n";
206// この更新では、統計表示オブザーバーは通知を受け取りません。
207$weatherData->setMeasurements(23.0, 60.0, 1015.5);
208
209echo "\n--- スクリプト終了 ---\n";
210
211?>

SplObserver::updateメソッドは、PHPの標準拡張機能であるSPL(Standard PHP Library)に定義されたインターフェースSplObserverが持つ、オブザーバーパターンで中心的な役割を果たすメソッドです。このメソッドは、監視対象である「主題(Subject)」の状態が変化した際に、その変更を「オブザーバー(Observer)」が受け取るために使用されます。

具体的には、主題のnotify()メソッドが呼び出されると、主題に登録されている全てのオブザーバーのupdate()メソッドが順次実行されます。update()メソッドはSplSubject $subjectという引数を一つ取ります。この引数には、通知を送ってきた主題自身のインスタンスが渡されます。オブザーバーはこの引数を通して、主題の現在の状態(サンプルコードでは気象データ)を問い合わせ、自身の表示内容を更新したり、必要な処理を実行します。

戻り値は「なし」と定義されており、このメソッドは主題の状態変化に応じてオブザーバーが何らかの処理を行うことに特化しています。サンプルコードでは、気象データ(WeatherDataクラス)が更新された際に、CurrentConditionsDisplayStatisticsDisplayといったオブザーバーのupdate()メソッドが呼び出され、それぞれの表示や統計情報が自動的に更新されています。キーワードの「php update文」は、データベースの更新文ではなく、オブザーバーパターンにおける「状態の更新通知」と、それを受けてオブザーバーが自身の状態を「更新」する動作を意味しています。

キーワードの「php update文」はデータベースのデータ更新を指すことが多いですが、ここで扱うSplObserver::updateメソッドは異なります。これは、Observerデザインパターンにおいて、監視対象(主題)から状態変更の通知を受け取った際に、監視者(オブザーバー)が実行する処理を定義するためのメソッドです。

引数として通知元のSplSubjectインスタンスを受け取り、その主題の現在の状態を取得して自身の処理に利用します。サンプルコードのようにinstanceofで受け取った主題の型を確認し、適切に処理を分岐させることが安全な実装のために重要です。このメソッドは特定の戻り値を持たず、通知を受け取ったオブザーバーが何らかの内部状態更新や表示処理を実行します。

関連コンテンツ