2012-02-02 12 views
9

私は数年前からPHPを扱ってきましたが、これまで明示的にシリアライズを扱う必要はなく、$_SESSIONしか使用していませんでした。今私は、特定のデータに対してシリアル化メカニズムを手動で実装する必要があるプロジェクトがあります。この問題は$_SESSIONにも当てはまると認識しています。PHPクラスの "Transient"プロパティ?

私はいくつかのプロパティを含むクラスを持っています。しかし、クラスにはいくつかのプロパティが含まれています。これらのプロパティには、大規模な配列が含まれている可能性があります(例:データベーステーブルのダンプ全体:100,000行、それぞれ100個のフィールド)。これが起こると、これはシリアライズ/デシリアライズする必要のあるクラスの1つです。大規模な配列を含むプロパティは、本質的に一時的な作業であり、必要に応じて再構築されるため、シリアル化する必要はありません。

Javaのこのような状況では、単にプロパティーをと宣言します。これはserialisaionから省略されます。残念ながら、PHPはそのような修飾子をサポートしていません。私はserialize方法私は別の過渡プロパティを追加するたびに更新する必要があるだろうとして、

class A implements Serializable 
{ 
    private $var_small = 1234; 
    private $var_big = array(...); //huge array, of course, not init in this way 

    public function serialize() 
    { 
     $vars = get_object_vars($this); 
     unset($vars['var_big']); 
     return serialize($vars); 
    } 

    public function unserialize($data) 
    { 
     $vars = unserialize($data); 
     foreach ($vars as $var => $value) { 
      $this->$var = $value; 
     } 
    } 
} 

は、しかし、これはかなり厄介です:に対処する

一つの方法は、それがこのようなものを持っていることです。また、継承が始まると、一時的なプロパティはサブクラスと親の両方にある可能性があるため、これはさらに複雑になります。私は知っている、それはまだ実行可能ですが、私は車輪を再発明するのではなく、可能な限り言語に委任することを好むでしょう。

したがって、一時的なプロパティを処理する最も良い方法は何ですか?それとも、PHPがこれをサポートしていますか?

答えて

7

Phpは__sleep magic methodを提供します。これにより、どの属性をシリアル化するかを選択できます。/

- :

<?php 

class A { 
    private $a = 'String a'; 
    private $b = 'String b'; 

    public function __sleep() { 
     echo "Sleep A\n"; 
     return array('a'); 
    } 
} 

class B extends A { 
    private $c = 'String c'; 
    private $d = 'String d'; 

    public function __sleep() { 
     echo "Sleep B\n"; 
     return array('c'); 
    } 
} 

class C extends A { 
    private $e = 'String e'; 
    private $f = 'String f'; 

    public function __sleep() { 
     echo "Sleep C\n"; 
     return array_merge(parent::__sleep(), array('e')); 
    } 
} 

$a = new A(); 
$b = new B(); 
$c = new C(); 

echo serialize($a) ."\n"; // Result: O:1:"A":1:{s:4:"Aa";s:8:"String a";} 
// called "Sleep A" (correct) 

echo serialize($b) ."\n"; // Result: O:1:"B":1:{s:4:"Bc";s:8:"String c";} 
// called just "Sleep B" (incorrect) 

echo serialize($c) ."\n"; // Caused: PHP Notice: serialize(): "a" returned as member variable from __sleep() but does not exist ... 

// When you declare `private $a` as `protected $a` that class C returns: 
// O:1:"C":2:{s:4:"*a";s:8:"String a";s:4:"Ce";s:8:"String e";} 
// which is correct and called are both: "Sleep C" and "Sleep A" 

だから、あなたが保護されたとして、それが宣言されていた場合にのみ、親データをシリアル化することができているようです。私は、継承はゲームのときに__sleep()仕事がないかテストしてみた

EDIT

<?php 

class A implements Serializable { 
    private $a = ''; 
    private $b = ''; 

    // Just initialize strings outside default values 
    public function __construct(){ 
     $this->a = 'String a'; 
     $this->b = 'String b'; 
    } 

    public function serialize() { 
     return serialize(array('a' => $this->a)); 
    } 

    public function unserialize($data){ 
     $array = unserialize($data); 
     $this->a = $array['a']; 
    } 
} 

class B extends A { 
    private $c = ''; 
    private $d = ''; 

    // Just initialize strings outside default values 
    public function __construct(){ 
     $this->c = 'String c'; 
     $this->d = 'String d'; 
     parent::__construct(); 
    } 

    public function serialize() { 
     return serialize(array('c' => $this->c, '__parent' => parent::serialize())); 
    } 

    public function unserialize($data){ 
     $array = unserialize($data); 
     $this->c = $array['c']; 
     parent::unserialize($array['__parent']); 
    } 
} 

$a = new A(); 
$b = new B(); 

echo serialize($a) ."\n"; 
echo serialize($b) ."\n"; 

$a = unserialize(serialize($a)); // C:1:"A":29:{a:1:{s:1:"a";s:8:"String a";}} 
$b = unserialize(serialize($b)); // C:1:"B":81:{a:2:{s:1:"c";s:8:"String c";s:8:"__parent";s:29:"a:1:{s:1:"a";s:8:"String a";}";}} 


print_r($a); 
print_r($b); 

/** Results: 
A Object 
(
    [a:A:private] => String a 
    [b:A:private] => 
) 
B Object 
(
    [c:B:private] => String c 
    [d:B:private] => 
    [a:A:private] => String a 
    [b:A:private] => 
) 
*/ 
:私は次のコードで Serializableのインタフェースでそれを試してみた

EDIT 2

soを集計してください:スーパークラス(プライベートクラスも同様にシリアライズする必要があります)にプライベートメンバーがない場合にのみ、__sleep()でクラスをシリアライズできます。 Serializableインターフェイスを実装して複雑なオブジェクトをシリアル化できますが、プログラミングオーバーヘッドが発生します。

+1

'__sleep'は親クラスのプライベートプロパティでは機能しません。したがって、継承が関与していない限り、唯一役に立ちます。 –

+0

@AleksGha!私は解決策を持っている!見てください:) – Vyktor

+0

ありがとう、それは実行可能なアプローチのように見えます。どのように動作するかを見るためにもう少し実験します。 –

0

__sleep and __wakeupを使用できます。前者の場合は、直列化したいオブジェクトのプロパティの名前の配列を指定します。このリストから「一時的な」メンバーを除外します。

__wakeupは、インスタンスが直列化解除されたときに直ちに呼び出されます。これを使用して、たとえば、一部の条件で非過渡特性を補充することができます。

関連する問題