ホームページ  >  記事  >  バックエンド開発  >  PHP のシリアル化と逆シリアル化の原理を直接見てみる

PHP のシリアル化と逆シリアル化の原理を直接見てみる

coldplay.xixi
coldplay.xixi転載
2020-07-20 17:23:002322ブラウズ

PHP のシリアル化と逆シリアル化の原理を直接見てみる

0. はじめに

オブジェクトのシリアル化および逆シリアル化関数については、詳細には説明しません。結果は、json に似た、PHP でカスタマイズされた文字列形式になります。

どの言語でもオブジェクトのシリアル化と逆シリアル化を設計する場合は、いくつかの問題を解決する必要があります。

オブジェクトがシリアル化された後、シリアル化の結果には自己記述関数があります (シリアル化の結果からオブジェクトの特定の型がわかります。

型を知るだけでは十分ではありません。もちろん、型も知る必要があります。対応する特定のvalue).

シリアル化時の権限制御、シリアル化フィールドなどをカスタマイズできます。たとえば、golang で行うと非常に便利です。

時間パフォーマンスの問題: 一部のパフォーマンス重視のシナリオでは、高パフォーマンスのサービス (シリアル化に protobuf をよく使用します) など、オブジェクトのシリアル化を抑制できません。

スペースのパフォーマンスの問題: シリアル化 その後の結果を維持できません。たとえば、int オブジェクトがメモリ内にあり、シリアル化後にデータ長が int の長さの 10 倍になる場合は、シリアル化アルゴリズムに問題があります。

この記事のみ「PHP コードの観点から PHP のシリアル化と逆シリアル化のプロセスを説明する」から始まります。シリアル化と逆シリアル化はオブジェクト データに対してのみ作用することに注意してください。これは、オブジェクト指向開発の経験がある人なら誰でも簡単に理解できるはずです。

関連する学習の推奨事項: 初心者から熟練度までの PHP プログラミング

1. メソッドのシリアル化と逆シリアル化 unserialize

php は、c...^_^ とは異なり、オブジェクトのシリアル化機能をネイティブに提供します。また、使い方も非常に簡単で、インターフェイスが 2 つだけです。

class fobnn
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj); //通过serialize接口序列化
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);//通过unserialize反序列化
$toobj->print();
fobnn
O:5:"fobnn":2:{s:7:"hack_id";i:1;s:16:"fobnnhack_name";s:5:"fobnn";}
fobnn

2 行目の出力を参照してください。この文字列は次の結果です。シリアル化。この構造は実は理解しやすいです。オブジェクト名/メンバー名でマッピングされていることがわかります。もちろん、アクセス権の異なるメンバーのシリアル化後のタグ名は若干異なります。

Based上で述べた 3 つの質問について、見てみましょう。

1. 自己記述関数

O:5:"fobnn":2 ここで、o はオブジェクト タイプとタイプ名を表します。は fobnn です。この形式では、次の 2 はメンバー オブジェクトが 2 つあることを示します。

メンバー オブジェクトに関しては、実際には同じサブ記述のセットです。これは再帰的な定義です。

自己記述関数は、主に文字列を通じてオブジェクトとメンバーの名前を記録することによって実装されます。

2. パフォーマンスの問題

PHP シリアル化の時間パフォーマンスは、この記事では分析されません。詳細は後述しますが、実際のシリアル化結果はjson/bsonで定義されたプロトコルと同様です プロトコルヘッダーがあり、プロトコルヘッダーには型が記述され、プロトコルボディには型に応じた値が記述されます シリアル化結果

2. 逆シリアル化のマジック メソッド

は、上記の 2 番目の問題に対応します。実際、PHP にも解決策があります。 1 つはマジック メソッドによるもので、2 つ目はカスタム シリアル化関数です。シリアル化の前に、まずマジック メソッド __sleep と __wakeup

class fobnn
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }
 public function __sleep()
 {
  return array("hack_name");
 }
 public function __wakeup()
 {
  $this->hack_name = 'haha';
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
fobnn
O:5:"fobnn":1:{s:16:"fobnnhack_name";s:5:"fobnn";}
haha

を導入しましょう。__sleep が最初に呼び出され、必要なメンバー名の配列が返されます。 , これにより、シリアル化する必要があるデータを制御できます。この場合、hack_name のみを返しました。結果では、hack_name メンバーのみがシリアル化されていることがわかります。

シリアル化が完了すると、 __wakeupにジャンプします。ここでは、データベースへの再接続などのフォローアップ作業を行うことができます。

3. シリアル化可能なインターフェイスのカスタマイズ

interface Serializable {
abstract public string serialize ( void )
abstract public void unserialize ( string $serialized )
}

このインターフェイスを通じて、シリアル化と逆シリアル化の動作をカスタマイズできます。この関数は主にシリアル化形式をカスタマイズするために使用できます。

class fobnn implements Serializable
{
 public $hack_id;
 private $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  echo $this->hack_name.PHP_EOL;
 }

 public function __sleep()
 {
  return array('hack_name');
 }

 public function __wakeup()
 {
  $this->hack_name = 'haha';
 }

 public function serialize()
 {
  return json_encode(array('id' => $this->hack_id ,'name'=>$this->hack_name ));
 }

 public function unserialize($var)
 {
  $array = json_decode($var,true);
  $this->hack_name = $array['name'];
  $this->hack_id = $array['id'];
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
fobnn
C:5:"fobnn":23:{{"id":1,"name":"fobnn"}}
fobnn

カスタム シリアル化インターフェイスを使用した後、魔法の方法は役に立ちません。

4.PHP 動的型と PHP 逆シリアル化

上記の自己記述関数なので、オブジェクトの型は次のようになります。

class fobnn
{
 public $hack_id;
 public $hack_name;
 public function __construct($name,$id)
 {
  $this->hack_name = $name;
  $this->hack_id = $id;
 }
 public function print()
 {
  var_dump($this->hack_name);
 }
}
$obj = new fobnn('fobnn',1);
$obj->print();
$serializedstr = serialize($obj);
echo $serializedstr.PHP_EOL;;
$toobj = unserialize($serializedstr);
$toobj->print();
$toobj2 = unserialize("O:5:\"fobnn\":2:{s:7:\"hack_id\";i:1;s:9:\"hack_name\";i:12345;}");
$toobj2->print();

を修正しますhack_name逆シリアル化結果はint型、 i: 12345

string(5) "fobnn"
O:5:"fobnn":2:{s:7:"hack_id";i:1;s:9:"hack_name";s:5:"fobnn";}
string(5) "fobnn"
int(12345)

オブジェクトが正常にシリアル化されて戻ったことがわかります!そして、正常に動作することができます! もちろん、PHP のこのメカニズムは柔軟で変更可能な構文を提供しますが、セキュリティ リスクも発生します。私たちは、PHP のシリアル化および逆シリアル化機能によって引き起こされるセキュリティ問題を引き続き分析していきます。

以上がPHP のシリアル化と逆シリアル化の原理を直接見てみるの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjb51.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。