【问题标题】:Encoding clone $this in JsonSerializable在 JsonSerializable 中编码克隆 $this
【发布时间】:2017-04-13 17:28:59
【问题描述】:

这种简化的情况会导致 PHP 段错误(退出 127):

class Datum implements \JsonSerializable{
  public function jsonSerialize(){
    return clone $this;
  }
}
echo json_encode(new Datum);

最后一行代码导致 exit(127)。我无法在当前环境中检索任何堆栈。

同时,删除 clone 令牌也可以。

是否有任何可能的解释为什么会发生这种情况?

【问题讨论】:

    标签: php recursion clone stack-overflow


    【解决方案1】:

    此代码导致无限递归。

    PHP JSON 模块似乎以这种方式支持JsonSerializable(伪代码):

    function json_encode($data){
        if($data instanceof JsonSerializable) return json_encode($data->jsonSerialize());
        else real_json_encode($data); // handling primitive data or arrays or pure data objects
    }
    

    如果您返回另一个 JsonSerializable 实例,json_encode 将尝试再次对其进行序列化,从而导致无限递归。

    这适用于return $this;,但是,可能是由于 json_encode 实现的有意变通方法,当返回的对象相同时,即返回 $this 时,它直接进入真正的 json_encode。但是,自 $a !== clone $a 以来,克隆对象不会发生这种情况。

    参考文献

    这个答案可以参考php-src来支持。

    // in php_json_encode_zval
    if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce)) {
        return php_json_encode_serializable_object(buf, val, options, encoder);
    }
    
    // in php_json_encode_serializable_object
    if ((Z_TYPE(retval) == IS_OBJECT) &&
        (Z_OBJ(retval) == Z_OBJ_P(val))) {
        /* Handle the case where jsonSerialize does: return $this; by going straight to encode array */
        PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);
        return_code = php_json_encode_array(buf, &retval, options, encoder);
    } else {
        /* All other types, encode as normal */
        return_code = php_json_encode_zval(buf, &retval, options, encoder);
        PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);
    }
    

    这些 sn-ps 证明 PHP 会将 return $this; 编码为一个数组(或作为一个不可序列化的对象),而返回任何其他东西会使 Z_OBJ(retval) == Z_OBJ_P(val) 为假,转到递归调用 @987654330 的 else 块再次@。

    TL;DR,简单的解决方案:return (array) $this; 而不是 clone $this;

    【讨论】:

      猜你喜欢
      • 2014-10-08
      • 1970-01-01
      • 2011-01-20
      • 1970-01-01
      • 2012-12-23
      • 2023-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多