I made a scheme similar to Anderson’s answer. But instead of implementing the JsonSerializable
in the date class, I make for the entire collection.
Thus:
class CustomJsonSerialize implements JsonSerializable
{
protected $data;
public function __construct(array $data)
{
$this->data = $data;
}
public function jsonSerialize()
{
$data_to_serialize = $this->data;
array_walk_recursive($data_to_serialize, function (&$value) {
if ($value instanceof \DateTime) {
$value = $value->format(DateTime::ISO8601);
}
});
return $data_to_serialize;
}
}
$data = [
'nome' => 'Wallace',
'data_cadastro' => new DateTime,
'idade' => 28,
'profissoes' => [
[
'nome' => 'Programador',
'data_inicio' => new DateTime('-5 years')
]
]
];
echo json_encode(new CustomJsonSerialize($data));
The answer is:
{
"nome": "Wallace",
"data_cadastro": "2018-08-09T14:56:38-0300",
"idade": 28,
"profissoes": [
{
"nome": "Programador",
"data_inicio": "2013-08-09T14:56:38-0300"
}
]
}
What is the importance of this?
Is that in certain cases you could not change the instance of DateTime
for another class implementation. Thus, creating a class that changes the collection, rather than changing the instance of DateTime
in itself, it is possible to convert all the values of the structure to the desired format.
In the case of PHP 7, it could be more useful still making an anonymous class!
$serialized_data = json_encode(new class ($data) implements JsonSerializable {
protected $data;
protected function __construct(array $data)
{
$this->data = $data;
}
public function jsonSerialize()
{
$data_to_serialize = $this->data;
array_walk_recursive($data_to_serialize, function (&$value) {
if ($value instanceof \DateTime) {
$value = $value->format(DateTime::ISO8601);
}
});
return $data_to_serialize;
}
});
Update: Imitating Javascript!
With Javascript, it is possible to make an implementation where the JSON.stringify
receives a callback in the second parameter (replacer
) that allows you to scroll through each item of the object passed, and can return a different value according to a condition.
Come to think of it, I’ve done something similar to PHP.
Source code:
function json_encode_callback($data, callable $callback, $options = 0)
{
$isIterable = static function ($data) {
return is_array($data) || $data instanceof \stdClass || $data instanceof Iterator;
};
$recursiveCallbackApply = static function ($data, callable $callback) use(&$recursiveCallbackApply, $isIterable) {
if (! $isIterable($data))
{
return $callback($data);
}
foreach ($data as $key => &$value) {
if ($isIterable($value)) {
$value = $recursiveCallbackApply($value, $callback);
continue;
}
$value = $callback($value, $key);
}
return $data;
};
return json_encode($recursiveCallbackApply($data, $callback), $options);
}
The above function basically traverses each item of a structure and checks for defirmin which will be serialized for json according to callback return.
Thus:
$obj = new stdClass;
$obj->date = new DateTime;
$obj->name = "Wallace";
$result = json_encode_callback($obj, function ($value) {
return $value instanceof \DateTime ? $value->format('c') : $value;
});
var_dump($result);
The result is:
string(53) "{"date":"2018-08-09T17:41:27-03:00","name":"Wallace"}"