我有以下类树:
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中的私有值,使其串行化和非串行化。
我该怎么做?
您可以使用反射类来完成此操作。您必须获得类本身及其每个父类的属性。可以使用ReflectionProperty
的getValue
和setValue
方法来获取和设置属性值,并结合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);
这似乎能满足你的需求。