I did a scheme similar to Anderson's answer. But instead of implementing JsonSerializable
in the date class, I do it for the entire collection.
So:
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?
In certain cases, you could not change the instance of DateTime
to another class implementation. So by creating a class that changes the collection, instead of changing the instance of DateTime
itself, you can convert all the values of the structure to the desired format.
In the case of PHP 7, it could be even more useful to make 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, you can do an implementation where JSON.stringify
receives a callback in the second parameter ( replacer
) that allows you to scroll through each item of the passed object, and can return a different value according to a condition. p>
Thinking about it, I did 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 in a structure and checks to determine what will be serialized to json according to callback return.
So:
$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"}"