在 JsonSerializable 中编码克隆 $this
Encoding clone $this in JsonSerializable
这种简化的情况会导致 PHP 段错误(退出 127):
class Datum implements \JsonSerializable{
public function jsonSerialize(){
return clone $this;
}
}
echo json_encode(new Datum);
最后一行代码导致 exit(127)。我无法在当前环境中检索任何堆栈。
与此同时,删除 clone
令牌有效。
是否有任何可能的解释为什么会发生这种情况?
此代码导致无限递归。
看来 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
}
如果您 return 另一个 JsonSerializable 实例,json_encode 将尝试再次序列化它,从而导致无限递归。
这适用于 return $this;
,但是,可能是由于 json_encode 的实施有意变通,当 returned 时它直接进入真实的 json_encode对象是相同的,即当 $this
被 return 编辑时。但是,自 $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);
}
这些片段证明 PHP 会将 return $this;
编码为数组(或不可序列化的对象),而 return 任何其他内容都会使 Z_OBJ(retval) == Z_OBJ_P(val)
错误,转到 else
块,它再次递归调用 php_json_encode_zval
。
TL;DR,简单的解决方案:return (array) $this;
而不是 clone $this;
。
这种简化的情况会导致 PHP 段错误(退出 127):
class Datum implements \JsonSerializable{
public function jsonSerialize(){
return clone $this;
}
}
echo json_encode(new Datum);
最后一行代码导致 exit(127)。我无法在当前环境中检索任何堆栈。
与此同时,删除 clone
令牌有效。
是否有任何可能的解释为什么会发生这种情况?
此代码导致无限递归。
看来 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
}
如果您 return 另一个 JsonSerializable 实例,json_encode 将尝试再次序列化它,从而导致无限递归。
这适用于 return $this;
,但是,可能是由于 json_encode 的实施有意变通,当 returned 时它直接进入真实的 json_encode对象是相同的,即当 $this
被 return 编辑时。但是,自 $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);
}
这些片段证明 PHP 会将 return $this;
编码为数组(或不可序列化的对象),而 return 任何其他内容都会使 Z_OBJ(retval) == Z_OBJ_P(val)
错误,转到 else
块,它再次递归调用 php_json_encode_zval
。