具有魔法属性的类上的json_encode

Veg*_*sen 5 php json

我正在尝试使用和json_encode所有具有魔法属性的对象数组.完全忽略这些,导致一个空对象数组(所有正常属性都是或).__get__setjson_encodeprivateprotected

所以,想象一下这个课:

class Foo
{
    public function __get($sProperty)
    {
        if ($sProperty == 'foo')
        {
            return 'bar!';
        }
        return null;
    }
}

$object = new Foo();
echo $object->foo; // echoes "foo"
echo $object->bar; // warning
echo json_encode($object); // "{}"
Run Code Online (Sandbox Code Playgroud)

我试过实施IteratorAggregateSerializable对类,但json_encode仍然没有看到我的魔法属性.由于我试图对这些对象的数组进行编码,AsJSON()因此类中的方法也不起作用.

更新!似乎这个问题很容易被误解.我怎么知道json_encode哪些"魔法属性"存在? IteratorAggregate没用.

BTW:PHP文档中术语是"动态实体".魔术属性是否真正存在是在争论语义.

Lev*_*son 23

PHP 5.4有一个名为的接口JsonSerializable.它有一个方法,jsonSerialize它将返回要编码的数据.通过实现它可以很容易地解决这个问题.


Tyl*_*ter 5

来自你的评论:

我问的是魔法属性,而不是方法. - Vegard Larsen 1分钟前

 

没有魔法财产这样的东西.

 

您现在拥有的只是一种魔术方法,当您尝试访问不可见属性时会调用该方法.

让我们再说一遍

 

$ obj-> foo不存在

 

魔术方法的实现方式不是PHP的关注点,它不能神奇地知道你正在使用你的魔法来"神奇地"使它看起来像$obj->foo.

如果某个属性不存在,则在它出现时不会将其放入对象中json_encode.

此外,即使json_encode知道它__get是活跃的,它也不会知道使用什么值来调用它.

  • 因此,我对对象中的属性“不存在”这一事实不感兴趣。请参阅修订后的问题。 (2认同)

Vol*_*erK 5

json_encode() 不会“询问”任何接口的对象。它通过调用 obj->get_properties() 直接获取表示对象属性的 HashTable 指针。然后它在这个 HashTable 上迭代(再次直接,没有使用诸如 Traversable、Iterator 等接口)并处理标记为 public 的元素。参见static void json_encode_array()ext/json/json.c
这使得无法在 json_encode() 的结果中显示属性,但不能作为 $obj->propname 访问。

编辑:我没有对其进行太多测试,忘记了“高性能”,但您可能想从

interface EncoderData {
  public function getData();
}

function json_encode_ex_as_array(array $v) {
  for($i=0; $i<count($v); $i++) {
    if ( !isset($v[$i]) ) {
      return false;
    }
  }
  return true;
}

define('JSON_ENCODE_EX_SCALAR', 0);
define('JSON_ENCODE_EX_ARRAY', 1);
define('JSON_ENCODE_EX_OBJECT', 2);
define('JSON_ENCODE_EX_EncoderDataObject', 3);

function json_encode_ex($v) {
  if ( is_object($v) ) {
    $type = is_a($v, 'EncoderData') ? JSON_ENCODE_EX_EncoderDataObject : JSON_ENCODE_EX_OBJECT;
  }
  else if ( is_array($v) ) {
    $type = json_encode_ex_as_array($v) ? JSON_ENCODE_EX_ARRAY : JSON_ENCODE_EX_OBJECT;
  }
  else {
    $type = JSON_ENCODE_EX_SCALAR;
  }

  switch($type) {
    case JSON_ENCODE_EX_ARRAY: // array [...]
      foreach($v as $value) {
        $rv[] = json_encode_ex($value);
      }
      $rv = '[' . join(',', $rv) . ']';
      break;
    case JSON_ENCODE_EX_OBJECT: // object { .... }
      $rv = array();
      foreach($v as $key=>$value) {
        $rv[] = json_encode((string)$key) . ':' . json_encode_ex($value);
      }
      $rv = '{' . join(',', $rv) .'}';
      break;
    case JSON_ENCODE_EX_EncoderDataObject:
      $rv = json_encode_ex($v->getData());
      break;
    default:
      $rv = json_encode($v);
  }
  return $rv;
}

class Foo implements EncoderData {
  protected $name;
  protected $child;

  public function __construct($name, $child) {
    $this->name = $name;
    $this->child = $child;

  }
  public function getData() {
    return array('foo'=>'bar!', 'name'=>$this->name, 'child'=>$this->child);
  }
}


$data = array();
for($i=0; $i<10; $i++) {
  $root = null;
  foreach( range('a','d') as $name ) {
    $root = new Foo($name, $root);
  }
  $data[] = 'iteration '.$i;
  $data[] = $root;
  $root = new StdClass;
  $root->i = $i;
  $data[] = $root;
}
$json = json_encode_ex($data);
echo $json, "\n\n\n";
$data = json_decode($json);
var_dump($data);
Run Code Online (Sandbox Code Playgroud)

至少有一个缺陷:它不处理递归,例如

$obj = new StdClass;
$obj->x = new StdClass;
$obj->x->y = $obj;
echo json_encode($obj); // warning: recursion detected...
echo json_encode_ex($obj); // this one runs until it hits the memory limit
Run Code Online (Sandbox Code Playgroud)