【问题标题】:PHP Serialization with private attributes & getters & setters具有私有属性 & getter & setter 的 PHP 序列化
【发布时间】:2018-07-16 16:08:30
【问题描述】:

我有一个基类,它使用 php 魔术方法 __get 和 __set 来修改扩展类中的私有属性。然后我为相关的私有属性构建了 setter getter 函数 (类似于在这里找到的 http://www.beaconfire-red.com/epic-stuff/better-getters-and-setters-php )

所以我的子类将如下所示:

class User extends BaseObject {
    public $id = -1;
    private $_status = "";


    function __construct($members = array()) {
        parent::__construct($members);

    }

    //Setter/Getter
    public function status($value = null) {
       if($value) {
           $this->_status = $value;

       } else {
           return $this->_status;
      }
}

现在,当我在基类中序列化这个作为 JsonSerialize 方法的对象时,序列化只会从子类中获取公共属性(即“Id”),但不会获取私有属性(即“ _状态”) 这是序列化函数:

 public function jsonSerialize() {
    $json = array();
    foreach($this as $key => $value) {

            $json[$key] = $value;

    }
    return $json;
}

上述基类中的方法有没有什么办法可以识别子类中的所有Getter,以便将它们包含在序列化中? 换句话说,我希望序列化同时包含“id”和“status”

我意识到我可以获取类上的所有方法并使用某种命名约定来标识 getter/setter,但我特别需要保持 getter/setter 名称与属性名称相同,即 _status 必须有一个 getter setter 调用 status() 那么还有其他方法可以识别这些特定功能吗?

【问题讨论】:

  • 在stackoverflow上阅读post
  • FWIW,如果那是你的实际二传手,你不应该使用它。它什么也没做。只需创建属性public 并分配给它。
  • 谢谢。它不是我的实际二传手。我的实际设置器正在设置一些其他属性。

标签: php getter-setter private-members json-serialization


【解决方案1】:

使用ReflectionReflectionProperty::setAccessible

    public function jsonSerialize()
    {
        $json = array();
        $class = new ReflectionClass($this);
        foreach ($class->getProperties() as $key => $value) {
            $value->setAccessible(true);
            $json[$value->getName()] = $value->getValue($this);

        }
        return $json;
    }

这是为了回答明确的问题。但我不确定您是否应该使用这种设计来解决您的问题。

【讨论】:

  • 那您有更好的解决方案吗?当然这已经在之前完成了......序列化具有私有属性和 getter/setter 函数的对象?最好的方法是什么?
  • 你有什么问题? :) 如果你想要一个对象表示,我会用我需要的所有吸气剂手动构建它。如果不能修改基类,那么Reflection就是办法
  • 我可以修改基类,因为我正在构建多个子类,这些子类都需要 getter/setter 序列化,所以我想把它放到基类中。我想我更喜欢 getter/setter 注册(我上面提到的)而不是反射
【解决方案2】:

我将采用不同的方法...我认为我更喜欢它而不是反思。 但我很想知道其他人是否同意。

我将根据访问时间在子类中注册每个 Getter/Setter,即将 getter/setter 名称存储在一个数组中。 在序列化时,我不仅会对所有公共属性进行交互,还会对注册的 getter/setter 进行交互。

当我在我的基类中注册(存储 getter/setter 名称)时,将其存储在一个名为 _getters 的数组中。

function __set($name,$value){
    if(method_exists($this, $name)){
        $this->$name($value);
        //save in getters list for serialization
        if(!in_array($name,$this->_getters))
            array_push($this->_getters,$name);
    }
    else{
        // Getter/Setter not defined so set as property of object
        $this->$name = $value;
    }
}

现在在我的序列化中,我还检索所有已注册的 getter 并将它们序列化。 它运作良好!

    public function jsonSerialize() {
    $json = array();
    //do public properties

    foreach($this as $key => $value) {
            $json[$key] = $value;

    }

    //do any getter setters
    foreach($this->_getters as $key => $getter) {
        $value = $this->$getter;
        $json[$getter] = $value;

    }
    return $json;
}

这种方法有什么问题吗?

【讨论】:

    【解决方案3】:

    也许有点不同的方法:

     public function toArray()
        {
            $descriptor = new \ReflectionClass(get_class($this));
            /** @var \ReflectionMethod[] $methods */
            $methods = $descriptor->getMethods(\ReflectionMethod::IS_PUBLIC);
            $array   = [];
            foreach ($methods as $method) {
                if (substr_compare('get', $method->getName(), 0, 3) === 0) {
                    $property         = lcfirst(substr($method->getName(), 3));
                    $value            = $method->invoke($this);
                    $array[$property] = $value;
                }
            }
    
            return $array;
        }
    

    除了返回数组,你也可以序列化它。这种方法在子类上使用公共 getter 方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      相关资源
      最近更新 更多