2013-07-04 21 views
1

我有以下分類:更改對象串行化是

class A /* Base class */ 
{ 
    private/protected/public $state 
} 

class B extends A /* Auto generated class, not to be modified */ 
{ 
    private $v 
    public function getV() { return $this->v; } 
    public function setV($val) { $this->v = $val; } 
} 

class C extends B { /* Custom code */ } 

只有一個A類有多個類,如B類,所有這些類都會有像C的子類。B類自動生成,不應該修改。

我在會話中存儲類型爲C的對象。我想要做的就是在每個實例中存儲一些狀態信息,就在PHP將其序列化之前,並且在非序列化時它會做一些事情。我希望所有這些都在A類中實現。

考慮到,我需要使用__sleep()Serializable接口。使用__sleep是不可能的,因爲PHP手冊中提到了什麼:

__sleep()不能在父類中返回私有屬性的名稱。這樣做會導致E_NOTICE級別錯誤。相反,你可以使用Serializable接口。

這意味着如果我睡一個類C的實例,我將失去在B中聲明的私有變量。所以我想使用Serializable,但由於某種原因,我根本無法讓它做什麼我想要。

實質上,我想要序列化對象,就好像我自己沒有實現任何序列化的東西,我只是想在$state之前添加信息。我試着用ReflectionObject->getProperties()來覆蓋所有的數據,但我似乎無法找到正確的方式來獲取並設置B類中的私有值,以便進行序列化和非序列化。

我該怎麼做?

回答

2

你可以使用Reflection類來做到這一點。你必須得到類本身的屬性和它的每個父類。獲取和設置屬性值可以使用ReflectionPropertygetValuesetValue方法,並結合setAccessible訪問私有和受保護的屬性。結合這些,我想出了以下代碼:

<?php 

class A implements Serializable /* Base class */ 
{ 
    protected $state; 

    public function serialize() 
    { 
    $this->state = "something"; 
    return serialize($this->_getState()); 
    } 

    public function unserialize($data) 
    { 
    $this->_setState(unserialize($data)); 
    } 

    protected function _getState() 
    { 
    $reflClass = new ReflectionClass(get_class($this)); 
    $values = array(); 
    while ($reflClass != null) 
    { 
     foreach ($reflClass->getProperties() as $property) 
     { 
     if ($property->getDeclaringClass() == $reflClass) 
     { 
      $property->setAccessible(true); 
      $values[] = array($reflClass->getName(), $property->getName(), $property->getValue($this)); 
     } 
     } 
     $reflClass = $reflClass->getParentClass(); 
    } 
    return $values; 
    } 

    protected function _setState($values) 
    { 
    foreach ($values as $_) 
    { 
     list($className, $propertyName, $propertyValue) = $_; 

     $property = new ReflectionProperty($className, $propertyName); 
     $property->setAccessible(true); 
     $property->setValue($this, $propertyValue); 
    } 
    } 

} 

class B extends A /* Auto generated class, not to be modified */ 
{ 
    private $v; 
    public function getV() { return $this->v; } 
    public function setV($val) { $this->v = $val; } 
} 

class C extends B { /* Custom code */ } 

$instance = new C(); 
$instance->setV("value"); 
$s = serialize($instance); 

$instance2 = unserialize($s); 
var_dump($instance, $instance2); 

這似乎是你想做的。