【PHP8.x】SplDoublyLinkedList::__serialize()メソッドの使い方
__serializeメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
__serializeメソッドは、PHP 8以降で導入された、オブジェクトをシリアライズ(直列化)する際に自動的に呼び出される特別な(マジック)メソッドです。シリアライズとは、プログラムで扱うオブジェクトの現在の状態を、ファイルに保存したり、ネットワークを通じて他のシステムに送信したりできる形式に変換する処理です。
SplDoublyLinkedListクラスでは、この__serializeメソッドが実行されると、現在の双方向リンクリストに格納されているすべての要素を順番に取得し、それらを一つの配列として返します。この返された配列が、シリアライズの対象となり、SplDoublyLinkedListオブジェクトの内部状態を正確に表現するデータとして保存されます。
この仕組みにより、SplDoublyLinkedListオブジェクトのインスタンスが持っている内容を正確に記録することが可能になります。保存されたデータは、後で__unserializeメソッドを利用することで、元のリストの状態を完全に復元するために用いられます。オブジェクトの状態を、プログラムが終了しても保持したり、異なるプロセス間で共有したりする必要がある場面で、この__serializeメソッドは非常に重要な役割を果たします。
構文(syntax)
1<?php 2 3class SplDoublyLinkedList 4{ 5 public function __serialize(): array 6 { 7 } 8}
引数(parameters)
引数なし
引数はありません
戻り値(return)
array
SplDoublyLinkedList オブジェクトをシリアライズ可能な配列形式で取得します。この配列は、オブジェクトの状態を保存し、後でデシリアライズするために使用されます。
サンプルコード
PHP SplDoublyLinkedList をカスタムシリアライズする
1<?php 2 3/** 4 * SplDoublyLinkedList を継承し、カスタムシリアライズ機能を追加するクラス。 5 * 6 * PHP 7.4 以降で導入された __serialize() および __unserialize() マジックメソッドを使用して、 7 * オブジェクトの状態をカスタマイズしてシリアライズおよびアンシリアライズします。 8 */ 9class CustomSerializableList extends SplDoublyLinkedList 10{ 11 private string $listName; 12 13 /** 14 * コンストラクタ 15 * 16 * @param string $name リストに付ける名前 17 */ 18 public function __construct(string $name = 'Default List') 19 { 20 $this->listName = $name; 21 } 22 23 /** 24 * オブジェクトのカスタムシリアライズロジックを提供します。 25 * 26 * このメソッドは serialize() 関数が呼び出されたときに実行されます。 27 * オブジェクトの状態を表現する配列を返す必要があります。 28 * 返された配列は、PHPによってシリアライズされ、unserialize() 時に __unserialize() に渡されます。 29 * 30 * ここでは、リストの名前とリスト内のすべての要素を配列として返します。 31 * 32 * @return array オブジェクトの状態を表すデータ配列 33 */ 34 public function __serialize(): array 35 { 36 // SplDoublyLinkedList の要素を配列に変換します。 37 // iterator_to_array() を使用すると、効率的にイテレータから配列を作成できます。 38 $elementsArray = iterator_to_array($this); 39 40 // リスト名と要素配列を結合して返します。 41 return [ 42 'listName' => $this->listName, 43 'elements' => $elementsArray, 44 ]; 45 } 46 47 /** 48 * オブジェクトのカスタムアンシリアライズロジックを提供します。 49 * 50 * このメソッドは unserialize() 関数が呼び出されたときに実行されます。 51 * __serialize() が返した配列 ($data) を受け取り、それを使ってオブジェクトの状態を再構築します。 52 * 53 * @param array $data __serialize() から受け取ったオブジェクトの状態データ 54 */ 55 public function __unserialize(array $data): void 56 { 57 // 受け取ったデータからリスト名をセットします。 58 $this->listName = $data['listName'] ?? 'Unnamed List'; 59 60 // 既存の要素を全て削除し、受け取ったデータでリストを再構築します。 61 // SplDoublyLinkedList は push メソッドで要素を追加できます。 62 while (!$this->isEmpty()) { 63 $this->pop(); // リストの末尾から要素を削除 64 } 65 foreach (($data['elements'] ?? []) as $element) { 66 $this->push($element); 67 } 68 } 69 70 /** 71 * リスト名を取得するヘルパーメソッド 72 * @return string リスト名 73 */ 74 public function getListName(): string 75 { 76 return $this->listName; 77 } 78} 79 80// ============================================================================== 81// サンプルコードの実行部分 82// ============================================================================== 83 84// キーワード「php serialize_precision」に関連する設定。 85// serialize_precision は浮動小数点数を文字列に変換する際の精度を定義します。 86// これを変更することで、シリアライズされたデータ内の浮動小数点数の表現が変わることを示します。 87 88// 元の serialize_precision の値を保存 89$originalSerializePrecision = ini_get('serialize_precision'); 90 91// serialize_precision を一時的に「5」に設定(デフォルトは 17 程度) 92// これにより、浮動小数点数のシリアライズ表現が短縮される可能性があります。 93ini_set('serialize_precision', '5'); 94echo "現在の serialize_precision: " . ini_get('serialize_precision') . "\n\n"; 95 96// カスタムリストのインスタンスを作成 97$myList = new CustomSerializableList('Experiment Data'); 98$myList->push(1.234567890123); // 精度の影響を受ける可能性のある浮動小数点数 99$myList->push(PHP_PI); // PHPの円周率定数 (例: 3.1415926535898) 100$myList->push('テキストデータ'); 101$myList->push(42); 102 103echo "--- 元のリストの内容 ---\n"; 104echo "リスト名: " . $myList->getListName() . "\n"; 105foreach ($myList as $item) { 106 echo " - " . (is_float($item) ? sprintf('%.15f', $item) . ' (float)' : (is_string($item) ? '"' . $item . '"' : $item)) . "\n"; 107} 108echo "\n"; 109 110// オブジェクトをシリアライズ 111// ここで CustomSerializableList::__serialize() メソッドが呼び出されます。 112$serializedObject = serialize($myList); 113 114echo "--- シリアライズされたデータ ---\n"; 115echo $serializedObject . "\n\n"; 116// シリアライズされた文字列の中に、浮動小数点数が設定された serialize_precision に従って短縮されていることを確認できます。 117// 例: float 型の値が "d:1.23457;" や "d:3.14159;" のように精度が丸められているのがわかります。 118 119// シリアライズされたデータをアンシリアライズ 120// ここで CustomSerializableList::__unserialize() メソッドが呼び出されます。 121$unserializedObject = unserialize($serializedObject); 122 123echo "--- アンシリアライズされたリストの内容 ---\n"; 124if ($unserializedObject instanceof CustomSerializableList) { 125 echo "リスト名: " . $unserializedObject->getListName() . "\n"; 126 foreach ($unserializedObject as $item) { 127 echo " - " . (is_float($item) ? sprintf('%.15f', $item) . ' (float)' : (is_string($item) ? '"' . $item . '"' : $item)) . "\n"; 128 } 129} else { 130 echo "エラー: オブジェクトのアンシリアライズに失敗しました。\n"; 131} 132echo "\n"; 133 134// serialize_precision を元の値に戻す 135ini_set('serialize_precision', $originalSerializePrecision); 136echo "serialize_precision を元の値に戻しました: " . ini_get('serialize_precision') . "\n"; 137
__serializeメソッドは、PHP 7.4以降で導入されたマジックメソッドで、オブジェクトをシリアライズ(保存可能な形式に変換)する際のカスタムロジックを定義するために使用されます。このメソッドは、serialize()関数が呼び出されたときに自動的に実行されます。
引数はなく、オブジェクトの現在の状態を表現する連想配列を返す必要があります。この返された配列はPHPによって内部的にシリアライズされ、後にunserialize()関数でオブジェクトを復元する際に、__unserialize()メソッドの引数として渡されます。これにより、開発者はオブジェクトの特定のプロパティだけをシリアライズしたり、シリアライズするデータを加工したりできます。
サンプルコードでは、SplDoublyLinkedListを継承したクラスで、リストの名前とリスト内の全ての要素を配列として__serializeから返すことで、独自のシリアライズ方法を実現しています。また、php serialize_precisionという設定は、シリアライズ時に浮動小数点数がどの程度の精度で表現されるかに影響を与え、データの忠実性に関わる重要な設定であることを示しています。
本コードはPHP 7.4以降の__serialize()と__unserialize()マジックメソッドを用いた、オブジェクトのカスタムシリアライズ例です。__serialize()はオブジェクトの状態を配列で返し、__unserialize()でそのデータを用いて復元しますが、両メソッド間でデータの一貫性を保つことが重要です。浮動小数点数の精度はserialize_precision設定により丸められる可能性があるため、厳密な値の保持が必要な場合は特に注意してください。最も重要なのは、unserialize()を信頼できない外部からの入力に決して使用しないことです。これはPHPオブジェクトインジェクションという重大なセキュリティ脆弱性を引き起こす危険性があるためです。
PHP 8: SplDoublyLinkedListのserialize/unserialize
1<?php 2 3/** 4 * SplDoublyLinkedList オブジェクトのシリアライズとデシリアライズのデモンストレーションを行います。 5 * 6 * PHP 8 以降では、オブジェクトのカスタムシリアライズには __serialize() と __unserialize() が推奨されます。 7 * SplDoublyLinkedList はこのメカニズムを内部的にサポートしており、 8 * PHP の標準関数である serialize() と unserialize() によって、 9 * その状態が正しく保存・復元されることを示します。 10 */ 11function demonstrateSplDoublyLinkedListSerialization(): void 12{ 13 // 1. SplDoublyLinkedList のインスタンスを作成し、データを追加します。 14 echo "--- 元の SplDoublyLinkedList オブジェクト ---" . PHP_EOL; 15 $originalList = new SplDoublyLinkedList(); 16 $originalList->push('Apple'); 17 $originalList->push('Banana'); 18 $originalList->unshift('Orange'); // リストの先頭に要素を追加 19 20 echo "元のリストの内容:" . PHP_EOL; 21 foreach ($originalList as $item) { 22 echo "- " . $item . PHP_EOL; 23 } 24 echo "元のリストの要素数: " . $originalList->count() . PHP_EOL . PHP_EOL; 25 26 // 2. オブジェクトをシリアライズします。 27 // serialize() 関数は、オブジェクトが __serialize() メソッドを実装している場合、 28 // そのメソッドの戻り値(配列)をシリアライズします。 29 // SplDoublyLinkedList はこの処理を内部的に行っています。 30 echo "--- オブジェクトのシリアライズ ---" . PHP_EOL; 31 $serializedData = serialize($originalList); 32 echo "シリアライズされたデータ(文字列):" . PHP_EOL; 33 echo $serializedData . PHP_EOL . PHP_EOL; 34 35 // 3. シリアライズされたデータからオブジェクトをデシリアライズします。 36 // unserialize() 関数は、PHP 8 ではオブジェクトの __unserialize() メソッドを呼び出し、 37 // 復元されたデータを使ってオブジェクトの状態を再構築します。 38 echo "--- オブジェクトのデシリアライズ ---" . PHP_EOL; 39 $unserializedList = unserialize($serializedData); 40 41 // デシリアライズが成功したかを確認し、内容を表示します。 42 if ($unserializedList instanceof SplDoublyLinkedList) { 43 echo "デシリアライズ成功!復元されたオブジェクトは SplDoublyLinkedList 型です。" . PHP_EOL; 44 echo "復元されたリストの内容:" . PHP_EOL; 45 foreach ($unserializedList as $item) { 46 echo "- " . $item . PHP_EOL; 47 } 48 echo "復元されたリストの要素数: " . $unserializedList->count() . PHP_EOL; 49 50 // 元のリストと復元されたリストの内容を簡単に比較します。 51 echo PHP_EOL . "--- 比較 ---" . PHP_EOL; 52 if ( 53 $originalList->count() === $unserializedList->count() && 54 $originalList->bottom() === $unserializedList->bottom() && // リストの末尾の要素 55 $originalList->top() === $unserializedList->top() // リストの先頭の要素 56 ) { 57 echo "元のリストと復元されたリストは、要素数および先頭・末尾の要素が一致しています。" . PHP_EOL; 58 } else { 59 echo "元のリストと復元されたリストは一致しない可能性があります。" . PHP_EOL; 60 } 61 62 } else { 63 echo "デシリアライズ失敗または予期せぬ型のオブジェクトが復元されました。" . PHP_EOL; 64 var_dump($unserializedList); // デシリアライズ結果を確認 65 } 66} 67 68// 関数を実行して、SplDoublyLinkedList のシリアライズとデシリアライズの動作を確認します。 69demonstrateSplDoublyLinkedListSerialization(); 70 71?>
__serializeメソッドは、PHP 8以降でオブジェクトのデータを永続化(保存)する際に推奨される特別なメカニズムです。このメソッドは引数を持ちませんが、自身のオブジェクトの状態を表す配列を返すことで、PHPの標準関数であるserialize()がそのデータを文字列に変換し、ファイルやデータベースなどに保存可能にします。
SplDoublyLinkedListクラスは、この__serializeメソッドを内部的に実装しており、リストの要素やその順序を正確に保存・復元できます。
サンプルコードでは、まずSplDoublyLinkedListに複数のデータを追加し、元のリストを作成します。次に、このリストオブジェクトをserialize()関数で文字列に変換します。その後、変換された文字列をunserialize()関数で元の状態のSplDoublyLinkedListオブジェクトとして復元します。これにより、元のリストと復元されたリストの内容、要素数が完全に一致することが確認でき、オブジェクトの状態が正しく保存・復元される様子を示しています。この機能は、プログラムが終了してもオブジェクトの情報を後で利用する際に非常に役立ちます。
PHP 8以降では、オブジェクトの状態を文字列に変換して保存し、後で復元する際にserialize()とunserialize()関数が推奨されます。SplDoublyLinkedListのようなPHP標準のデータ構造は、この処理を内部的に__serialize()と__unserialize()メソッドを通じて適切に処理します。これにより、サンプルコードのように開発者が特別なコードを書かなくても、リストの要素や順序を保ったまま安全に保存・復元できます。デシリアライズ後は、必ずinstanceof演算子で復元されたオブジェクトの型を確認し、期待通りのSplDoublyLinkedListが返されているか検証することが重要です。また、信頼できないデータソースからの文字列をunserialize()すると、セキュリティ上の脆弱性につながる可能性があるため、利用には十分な注意が必要です。