Кодирование клона $ this в JsonSerializable

Этот упрощенный случай приводит к segfault PHP (выход 127):

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

Последняя строка кода приводит к выходу (127). Я не могу получить какой-либо стек в моей текущей среде.

Между тем, удаляя clone токен работает.

Есть ли возможное объяснение, почему это происходит?

4

Решение

Этот код приводит к бесконечной рекурсии.

Похоже, что модуль 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, где он переходит прямо к реальному json_encode, когда возвращаемый объект идентичен, то есть когда $this возвращается Однако это не происходит для клонированных объектов, так как $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; как массив (или как не сериализуемый объект), при возврате чего-либо еще Z_OBJ(retval) == Z_OBJ_P(val) ложь, иду к else блок, который вызывает рекурсивно php_json_encode_zval снова.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]