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 类中的私有值以进行序列化和反序列化。

我该怎么做呢?

4

1 回答 1

2

您可以使用反射类来做到这一点。您必须获取类本身及其每个父类的属性。可以使用ReflectionProperty'sgetValuesetValue方法来获取和设置属性值,并结合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);

这似乎做你想做的事。

于 2013-07-04T12:15:37.300 回答