【问题标题】:PHP json_encode class private membersPHP json_encode 类私有成员
【发布时间】:2011-08-10 04:20:15
【问题描述】:

我正在尝试对 PHP 中的一些对象进行 JSON 编码,但我遇到了一个问题:我想对由类私有成员保存的数据进行编码。 我发现这段代码通过调用如下的编码函数来编码这个对象:

public function encodeJSON() 
{ 
    foreach ($this as $key => $value) 
    { 
        $json->$key = $value; 
    } 
    return json_encode($json); 
}

但是,这仅在我要编码的对象内部不包含其他对象时才有效,就是这种情况。我怎样才能不仅对“外部”对象进行编码,而且对作为对象的任何成员也进行编码?

【问题讨论】:

  • 要么使用公共方法,要么使用反射

标签: php json


【解决方案1】:

用私有属性序列化对象的最佳方法是实现\JsonSerializable接口,然后实现自己的JsonSerialize方法返回你需要序列化的数据。

<?php

class Item implements \JsonSerializable
{
    private $var;
    private $var1;
    private $var2;

    public function __construct()
    {
        // ...
    }

    public function jsonSerialize()
    {
        $vars = get_object_vars($this);

        return $vars;
    }
}

json_encode 现在将正确序列化您的对象。

【讨论】:

    【解决方案2】:

    如果你使用的是 php 5.4,你可以使用 JsonSerializable 接口:http://www.php.net/manual/en/class.jsonserializable.php

    您只需在您的类中实现一个 jsonSerialize 方法,该方法返回您想要编码的任何内容。

    然后当你将你的对象传入 json_encode 时,它​​会对 jsonSerialize 的结果进行编码。

    【讨论】:

      【解决方案3】:

      我认为@Petah 有最好的方法,但是那样你会丢失数组或对象的属性。所以我添加了一个递归函数:

      function json_encode_private($object) {
      
          function extract_props($object) {
              $public = [];
      
              $reflection = new ReflectionClass(get_class($object));
      
              foreach ($reflection->getProperties() as $property) {
                  $property->setAccessible(true);
      
                  $value = $property->getValue($object);
                  $name = $property->getName();
      
                  if(is_array($value)) {
                      $public[$name] = [];
      
                      foreach ($value as $item) {
                          if (is_object($item)) {
                              $itemArray = extract_props($item);
                              $public[$name][] = $itemArray;
                          } else {
                              $public[$name][] = $item;
                          }
                      }
                  } else if(is_object($value)) {
                      $public[$name] = extract_props($value);
                  } else $public[$name] = $value;
              }
      
              return $public;
          }
      
          return json_encode(extract_props($object));
      }
      

      编辑:在数组循环中添加了 is_object() 检查,以避免当数组元素不是对象(如字符串或数字)时在下一次 extract_props() 调用中出现 get_class() 异常。 p>

      【讨论】:

      • 对于测试/调试重度嵌套对象非常有用。非常感谢:)
      • 这是我为具有嵌套对象属性的对象找到的第一个答案。这也适用于 PHP 5.3.3。谢谢。 +1
      • 要覆盖数组的值,您需要一个额外的包装器: private static function extract_props_obj_or_array($objectOrArray) { if (is_array($objectOrArray)) { $result = array(); foreach ($objectOrArray as $object) { $result[] = extract_props($object); } 返回$结果; } else { // 我们现在知道这不是一个数组.... return extract_props_object($objectOrArray); } }
      • 我在PHP console_log debug method for WordPress中实现了这个功能。
      • 我发现的实现存在问题。在调用$prop-&gt;getValue() 之前,您必须检查isset( get_class( $object ), $name ),否则如果属性未设置,您会收到PHP 通知。
      【解决方案4】:

      无论如何。您需要在您的类中创建公共方法以返回其所有字段 json 编码

      public function getJSONEncode() {
          return json_encode(get_object_vars($this));
      }
      

      【讨论】:

      • 如果某些字段又具有私有变量,这是否有效?我猜它不会,因为 json_encode 不能在它们上递归调用。
      • php.net/manual/en/function.get-object-vars.php 中的示例代码似乎表明,如果在类中声明该方法,它可以工作,因为它可以访问其成员。
      【解决方案5】:

      我认为这可能是使用特征的一个很好的案例

      使用以下 guist,我在我的应用程序的多个点实现了 jsonSerializable interface,同时保持代码可管理

      https://gist.github.com/zburgermeiszter/7dc5e65b06bb34a325a0363726fd8e14

      trait JsonSerializeTrait
      {
          function jsonSerialize()
          {
              $reflect = new \ReflectionClass($this);
              $props   = $reflect->getProperties(\ReflectionProperty::IS_STATIC | \ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED | \ReflectionProperty::IS_PRIVATE);
      
              $propsIterator = function() use ($props) {
                  foreach ($props as $prop) {
                      yield $prop->getName() => $this->{$prop->getName()};
                  }
              };
      
              return iterator_to_array($propsIterator());
          }
      }
      

      那么你只需要这样做

      class YourClass implements JsonSerializable 
      {
          use JsonSerializeTrait;
      
          ... normal encapsulated code...
      }
      

      【讨论】:

        【解决方案6】:
        public function jsonSerialize()
        {
            $objectArray = [];
            foreach($this as $key => $value) {
                $objectArray[$key] = $value;
            }
        
            return json_encode($objectArray);
        }
        

        我个人认为这是一种方法。它类似于 Petah 的,除了它很好地符合封装,因为数组是从对象填充的。

        将此函数放入您的对象中或作为您的对象使用的特征。不过各有各的。

        【讨论】:

        • 这样做没有意义 - 如果您需要获取私有变量,上述 Oleg 的回答可以正常工作。
        【解决方案7】:

        这将打印一个 JSON,其中包含 foo 类的所有属性(公共、私有和受保护):

        $reflection = new ReflectionClass('Foo');
        $properties = $reflection->getdefaultProperties();
        
        echo json_encode($properties);
        

        它适用于任何环境。

        【讨论】:

          【解决方案8】:

          您只能在类中对对象的私有成员进行编码。附带说明一下,json_enocde 函数对您不起作用吗? http://php.net/manual/en/function.json-encode.php

          【讨论】:

          • 是的,在类上下文中它可以工作。但是,当某些类成员也是具有私有成员的对象时,我应该如何处理?
          【解决方案9】:

          使用反射你可以json_encode私有属性,虽然它不是最佳实践:

          function json_encode_private($object) {
              $public = [];
              $reflection = new ReflectionClass($object);
              foreach ($reflection->getProperties() as $property) {
                  $property->setAccessible(true);
                  $public[$property->getName()] = $property->getValue($object);
              }
              return json_encode($public);
          }
          

          例如

          class Foo {
              public $a = 1;
              public $b = 2;
          }
          class Bar {
              private $c = 3;
              private $d = 4;
          }
          
          var_dump(json_encode(new Foo()));
          var_dump(json_encode_private(new Bar()));
          

          输出:

          string(13) "{"a":1,"b":2}"
          string(13) "{"c":3,"d":4}"
          

          http://codepad.viper-7.com/nCcKYW

          【讨论】:

            猜你喜欢
            • 2011-02-24
            • 1970-01-01
            • 1970-01-01
            • 2017-12-22
            • 2014-09-02
            • 2019-12-29
            • 2015-11-15
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多