【PHP8.x】ArrayObject::__serialize()メソッドの使い方
__serializeメソッドの使い方について、初心者にもわかりやすく解説します。
基本的な使い方
__serializeメソッドは、ArrayObjectオブジェクトをシリアライズ(直列化)する際のデータ表現をカスタマイズするために実行されるメソッドです。このメソッドはマジックメソッドの一種であり、serialize()関数がArrayObjectのインスタンスを処理する際に自動的に呼び出されます。通常、オブジェクトをシリアライズすると全てのプロパティが保存されますが、__serializeメソッドをクラスに実装することで、どのデータをどのような形式で保存するかを開発者が明示的に制御できます。このメソッドは、シリアライズしたいプロパティの名前をキー、その値をバリューとする連想配列を返す必要があります。返された配列が、そのオブジェクトのシリアライズされたデータ表現となります。例えば、オブジェクトの一部のプロパティだけを保存したり、特定の計算結果を加えて保存したりすることが可能です。このメソッドは、対となる__unserializeメソッドと一緒に使用することで、オブジェクトの状態を正確に保存し、後から完全に復元する仕組みを構築するために役立ちます。
構文(syntax)
1<?php 2class MyArrayObject extends ArrayObject 3{ 4 public function __serialize(): array 5 { 6 return parent::__serialize(); 7 } 8}
引数(parameters)
引数なし
引数はありません
戻り値(return)
array
ArrayObject::__serialize メソッドは、ArrayObject オブジェクトをシリアライズ可能にするための配列を返します。
サンプルコード
PHP ArrayObject の __serialize と serialize_precision を理解する
1<?php 2 3/** 4 * ArrayObjectを継承し、カスタムのシリアライズロジック (__serialize) を持つクラス。 5 * このクラスは、ArrayObjectの通常のデータに加えて、カスタムの浮動小数点数プロパティもシリアライズします。 6 */ 7class MyCustomSerializableArray extends ArrayObject 8{ 9 private float $myFloatValue; 10 11 /** 12 * コンストラクタ。ArrayObjectの初期化に加え、カスタムの浮動小数点数を設定します。 13 * 14 * @param array $input 初期データ 15 * @param int $flags フラグ 16 * @param string $iteratorClass イテレータクラス名 17 */ 18 public function __construct(array $input = [], int $flags = 0, string $iteratorClass = ArrayIterator::class) 19 { 20 parent::__construct($input, $flags, $iteratorClass); 21 // シリアライズされる浮動小数点数。この値の精度が serialize_precision の影響を受けます。 22 $this->myFloatValue = 123.4567890123456789; 23 } 24 25 /** 26 * オブジェクトが serialize() 関数によってシリアライズされる際に呼び出されるマジックメソッド。 27 * このメソッドは、オブジェクトの状態を表現する連想配列を返します。 28 * ここで返される配列が PHP の serialize() 関数によって処理されます。 29 * 30 * @return array オブジェクトの状態を表す連想配列 31 */ 32 public function __serialize(): array 33 { 34 // ArrayObjectの内部データと、カスタムの浮動小数点数プロパティを配列に含めて返します。 35 // この配列の 'custom_float_property' の値が serialize_precision の影響を受けます。 36 return [ 37 'array_data' => $this->getArrayCopy(), // ArrayObjectの内部データを取得 38 'custom_float_property' => $this->myFloatValue, // カスタムの浮動小数点数プロパティ 39 ]; 40 } 41 42 /** 43 * オブジェクトが unserialize() 関数によってアンシリアライズされる際に呼び出されるマジックメソッド。 44 * __serialize() から返されたデータを使用して、オブジェクトの状態を復元します。 45 * 46 * @param array $data __serialize() から返されたデータ 47 */ 48 public function __unserialize(array $data): void 49 { 50 // ArrayObjectの内部データを復元 51 foreach ($data['array_data'] as $key => $value) { 52 $this[$key] = $value; 53 } 54 // カスタムの浮動小数点数プロパティを復元 55 $this->myFloatValue = $data['custom_float_property']; 56 } 57 58 /** 59 * カスタムの浮動小数点数プロパティの値を取得します。 60 * 61 * @return float 浮動小数点数プロパティの値 62 */ 63 public function getMyFloatValue(): float 64 { 65 return $this->myFloatValue; 66 } 67} 68 69// ----------------------------------------------------------- 70// サンプルコード実行部分 71// ----------------------------------------------------------- 72 73echo "PHP Version: " . PHP_VERSION . "\n\n"; 74 75// MyCustomSerializableArray クラスのインスタンスを作成 76$initialData = ['name' => 'Alice', 'id' => 101]; 77$obj = new MyCustomSerializableArray($initialData); 78 79echo "Original custom float value: " . $obj->getMyFloatValue() . "\n\n"; 80 81// PHPのデフォルトの serialize_precision 設定でシリアライズ 82echo "--- Default serialize_precision ---\n"; 83// 現在の serialize_precision の値を取得 (通常は '17') 84$defaultPrecision = ini_get('serialize_precision'); 85echo "Current serialize_precision: " . $defaultPrecision . "\n"; 86 87// オブジェクトをシリアライズ 88$serializedDefault = serialize($obj); 89echo "Serialized string: " . $serializedDefault . "\n"; 90 91// シリアライズされたデータをアンシリアライズし、浮動小数点数の精度を確認 92$unserializedDefault = unserialize($serializedDefault); 93echo "Unserialized float value: " . $unserializedDefault->getMyFloatValue() . "\n\n"; 94 95 96// serialize_precision を -1 (完全な精度) に設定してシリアライズ 97echo "--- serialize_precision set to -1 (full precision) ---\n"; 98ini_set('serialize_precision', -1); // -1 は利用可能な全ての桁数を保持するように指定 99$fullPrecision = ini_get('serialize_precision'); 100echo "Current serialize_precision: " . $fullPrecision . "\n"; 101 102// オブジェクトを再度シリアライズ 103$serializedFull = serialize($obj); 104echo "Serialized string: " . $serializedFull . "\n"; 105 106// シリアライズされたデータをアンシリアライズし、浮動小数点数の精度を確認 107$unserializedFull = unserialize($serializedFull); 108echo "Unserialized float value: " . $unserializedFull->getMyFloatValue() . "\n\n"; 109 110 111// serialize_precision を 5 に設定してシリアライズ 112echo "--- serialize_precision set to 5 (limited precision) ---\n"; 113ini_set('serialize_precision', 5); // 精度を5桁に制限 114$limitedPrecision = ini_get('serialize_precision'); 115echo "Current serialize_precision: " . $limitedPrecision . "\n"; 116 117// オブジェクトを再度シリアライズ 118$serializedLimited = serialize($obj); 119echo "Serialized string: " . $serializedLimited . "\n"; 120 121// シリアライズされたデータをアンシリアライズし、浮動小数点数の精度を確認 122$unserializedLimited = unserialize($serializedLimited); 123echo "Unserialized float value: " . $unserializedLimited->getMyFloatValue() . "\n\n"; 124 125// スクリプト終了時に ini 設定は自動的にリセットされますが、明示的に元に戻すことも可能です。 126ini_set('serialize_precision', $defaultPrecision);
PHPのArrayObject::__serializeメソッドは、クラスのインスタンスがserialize()関数によって文字列に変換される際に、どのデータを保存するかをカスタマイズするためのマジックメソッドです。このメソッドは引数を受け取らず、オブジェクトの状態を表す連想配列を戻り値として返します。この戻り値の配列が、PHPのserialize()関数によって実際に処理されます。
サンプルコードでは、ArrayObjectを継承したMyCustomSerializableArrayクラスを定義し、通常のArrayObjectのデータに加えて、myFloatValueという独自の浮動小数点数プロパティを保持しています。__serializeメソッド内で、親クラスのデータとこのカスタムプロパティをまとめた配列を返すことで、オブジェクト全体をシリアライズできるように実装されています。
特に、このコードは浮動小数点数のシリアライズ精度を制御するPHPの設定項目であるserialize_precisionが、__serializeメソッドから返される浮動小数点数にどのように影響するかを示しています。serialize_precisionの値を変更することで、シリアライズされる浮動小数点数の桁数が変わり、その結果、unserialize()関数でオブジェクトを復元した際の浮動小数点数の精度も変化することが確認できます。これにより、オブジェクトの永続化やデータ転送時に、浮動小数点数の精度をどのように扱うべきかの理解を深めることができます。
ArrayObject::__serializeメソッドは、オブジェクトがPHPのserialize()関数でデータ化される際に、どのような情報を保存するかをカスタムするマジックメソッドです。このメソッドは必ず配列を返し、その配列の内容がシリアライズされます。また、__unserializeメソッドとペアで機能し、シリアライズされたデータからのオブジェクト復元を担います。特に、浮動小数点数を扱う場合、php.ini設定のserialize_precisionに注意が必要です。この設定値によってシリアライズ時の浮動小数点数の精度が変わるため、アンシリアライズ後に元の値と誤差が生じる可能性があります。完全な精度で保存したい場合は、serialize_precisionを-1に設定するなどの考慮が必要です。ArrayObjectを継承している場合、その内部データを保存するにはgetArrayCopy()などで明示的に取得し、__serializeの戻り値の配列に含める必要があります。
PHP ArrayObjectの__serializeでカスタムシリアライズする
1<?php 2 3/** 4 * ArrayObject を継承したカスタムクラス。 5 * オブジェクトのシリアライズ・デシリアライズの動作をカスタマイズする方法を示します。 6 */ 7class MyCustomArrayObject extends ArrayObject 8{ 9 private string $authorName; 10 private int $versionId; 11 12 /** 13 * コンストラクタ 14 * 15 * @param string $authorName 著者名 16 * @param int $versionId バージョンID 17 * @param array $input ArrayObjectの初期データ 18 * @param int $flags ArrayObjectの動作フラグ 19 * @param string $iterator_class イテレータクラス名 20 */ 21 public function __construct( 22 string $authorName, 23 int $versionId, 24 array $input = [], 25 int $flags = 0, 26 string $iterator_class = "ArrayIterator" 27 ) { 28 parent::__construct($input, $flags, $iterator_class); 29 $this->authorName = $authorName; 30 $this->versionId = $versionId; 31 } 32 33 /** 34 * PHP 8で導入されたマジックメソッドで、オブジェクトが serialize() される際に呼び出されます。 35 * このメソッドは、シリアライズするデータを連想配列として返します。 36 * この返された配列が、serialize() 関数の結果に含まれます。 37 * 38 * @return array シリアライズするプロパティとその値を含む配列 39 */ 40 public function __serialize(): array 41 { 42 // 独自のプロパティと、親クラス (ArrayObject) の内部データを結合して返します。 43 // getArrayCopy() は ArrayObject の内部データを配列として取得します。 44 return [ 45 'authorName' => $this->authorName, 46 'versionId' => $this->versionId, 47 'arrayData' => $this->getArrayCopy(), // ArrayObject の内部データ 48 ]; 49 } 50 51 /** 52 * PHP 8で導入されたマジックメソッドで、オブジェクトが unserialize() される際に呼び出されます。 53 * __serialize() が返したデータを受け取り、オブジェクトの状態を復元します。 54 * 55 * @param array $data __serialize() が返したデータ配列 56 */ 57 public function __unserialize(array $data): void 58 { 59 $this->authorName = $data['authorName']; 60 $this->versionId = $data['versionId']; 61 // ArrayObject の内部データを復元します。 62 // exchangeArray() は ArrayObject の内部データを置き換えます。 63 $this->exchangeArray($data['arrayData']); 64 } 65 66 /** 67 * 著者名を取得します。 68 */ 69 public function getAuthorName(): string 70 { 71 return $this->authorName; 72 } 73 74 /** 75 * バージョンIDを取得します。 76 */ 77 public function getVersionId(): int 78 { 79 return $this->versionId; 80 } 81} 82 83// --- サンプルコードの実行 --- 84 85// 1. MyCustomArrayObject のインスタンスを作成し、初期データを設定 86echo "--- オリジナルオブジェクトの作成 ---" . PHP_EOL; 87$originalObject = new MyCustomArrayObject('Taro Yamada', 12345, ['setting_a' => true, 'setting_b' => 'value']); 88$originalObject['additional_item'] = 'extra data'; // ArrayObject として追加のデータを格納 89 90echo "オリジナルオブジェクトの名前: " . $originalObject->getAuthorName() . PHP_EOL; 91echo "オリジナルオブジェクトのID: " . $originalObject->getVersionId() . PHP_EOL; 92echo "オリジナルオブジェクトのsetting_a: " . ($originalObject['setting_a'] ? 'true' : 'false') . PHP_EOL; 93echo "オリジナルオブジェクトのadditional_item: " . $originalObject['additional_item'] . PHP_EOL; 94echo PHP_EOL; 95 96// 2. オブジェクトをシリアライズ (文字列に変換) 97echo "--- オブジェクトのシリアライズ ---" . PHP_EOL; 98$serializedString = serialize($originalObject); 99echo "シリアライズされた文字列: " . $serializedString . PHP_EOL; 100echo PHP_EOL; 101 102// 3. シリアライズされた文字列をデシリアライズ (オブジェクトに復元) 103echo "--- オブジェクトのデシリアライズ ---" . PHP_EOL; 104$restoredObject = unserialize($serializedString); 105 106// 4. 復元されたオブジェクトが元の状態と同じか確認 107echo "復元されたオブジェクトの名前: " . $restoredObject->getAuthorName() . PHP_EOL; 108echo "復元されたオブジェクトのID: " . $restoredObject->getVersionId() . PHP_EOL; 109echo "復元されたオブジェクトのsetting_a: " . ($restoredObject['setting_a'] ? 'true' : 'false') . PHP_EOL; 110echo "復元されたオブジェクトのadditional_item: " . $restoredObject['additional_item'] . PHP_EOL; 111echo PHP_EOL; 112 113// 復元されたオブジェクトがオリジナルと等しいか検証 114if ( 115 $originalObject->getAuthorName() === $restoredObject->getAuthorName() && 116 $originalObject->getVersionId() === $restoredObject->getVersionId() && 117 $originalObject['setting_a'] === $restoredObject['setting_a'] && 118 $originalObject['additional_item'] === $restoredObject['additional_item'] 119) { 120 echo "✔ オブジェクトは正しくシリアライズされ、元の状態に復元されました。" . PHP_EOL; 121} else { 122 echo "✖ オブジェクトのシリアライズ・デシリアライズに失敗しました。" . PHP_EOL; 123} 124?>
PHP 8で導入されたArrayObject::__serializeメソッドは、オブジェクトのデータを文字列に変換するserialize()関数が呼び出される際に実行される特殊なマジックメソッドです。このメソッドは、オブジェクトをファイルに保存したり、ネットワーク越しに転送したりする際に、その状態を正しく記録するために使用されます。
__serializeメソッドの主な目的は、オブジェクトのどのプロパティや内部データをシリアライズの対象とするかを、開発者が細かく制御することです。このメソッドは引数を一切受け取らず、戻り値として連想配列(array)を返します。この返された配列に含まれるデータが、serialize()関数の最終的な結果として生成される文字列に反映されます。
サンプルコードでは、ArrayObjectを継承したMyCustomArrayObjectクラスが、独自のプロパティ(authorNameやversionId)とArrayObjectとしてのデータを持っています。__serializeメソッド内では、これらの独自プロパティと、getArrayCopy()メソッドで取得したArrayObjectの内部データを一つの連想配列にまとめ、その配列を返しています。これにより、serialize()された文字列には、カスタムクラスのすべての重要な情報が正しく含まれるようになります。
そして、シリアライズされた文字列からオブジェクトを復元するunserialize()関数の際には、対となる__unserializeメソッドが自動的に呼び出されます。この__unserializeメソッドは、__serializeが返した配列データを受け取り、それを使ってオブジェクトのプロパティやArrayObjectの内部データをexchangeArray()メソッドで復元し、元の状態に戻します。このように__serializeと__unserializeを組み合わせることで、複雑なオブジェクトでも安全にデータの保存と復元が行えるのです。
PHP 8で導入された__serializeと__unserializeは、オブジェクトを安全に永続化させるためのマジックメソッドです。これらのメソッドを実装する際は、カスタムプロパティだけでなく、親クラスであるArrayObjectの内部データも含め、オブジェクトの全ての状態が正確にシリアライズされるように注意してください。__serializeで返した配列は、__unserializeで元の状態に完璧に復元される必要があります。最も重要な点として、信頼できないソースから取得したシリアライズデータをunserializeすることは、深刻なセキュリティ上の脆弱性を引き起こす可能性があるため、絶対に避けてください。データの改ざんがないか厳重に確認することが重要です。