Eu estava vagando pelo php.net em busca de informações sobre como serializar objetos PHP para JSON, quando me deparei com a nova interface JsonSerializable . É apenas PHP> = 5.4 , porém, e estou executando em um ambiente 5.3.x.
Como esse tipo de funcionalidade é alcançado em PHP <5.4 ?
Ainda não trabalhei muito com JSON, mas estou tentando oferecer suporte a uma camada de API em um aplicativo, e despejar o objeto de dados ( que de outra forma seria enviado para a visualização ) em JSON seria perfeito.
Se eu tentar serializar o objeto diretamente, ele retorna uma string JSON vazia; o que é porque eu presumo json_encode()
que não saiba o que diabos fazer com o objeto. Devo reduzir recursivamente o objeto em um array e, em seguida, codificá- lo ?
Exemplo
$data = new Mf_Data();
$data->foo->bar['hello'] = 'world';
echo json_encode($data)
produz um objeto vazio:
{}
var_dump($data)
no entanto, funciona como esperado:
object(Mf_Data)#1 (5) {
["_values":"Mf_Data":private]=>
array(0) {
}
["_children":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["foo"]=>
object(Mf_Data)#2 (5) {
["_values":"Mf_Data":private]=>
array(0) {
}
["_children":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["bar"]=>
object(Mf_Data)#3 (5) {
["_values":"Mf_Data":private]=>
array(1) {
[0]=>
array(1) {
["hello"]=>
string(5) "world"
}
}
["_children":"Mf_Data":private]=>
array(0) {
}
["_parent":"Mf_Data":private]=>
*RECURSION*
["_key":"Mf_Data":private]=>
string(3) "bar"
["_index":"Mf_Data":private]=>
int(0)
}
}
}
["_parent":"Mf_Data":private]=>
*RECURSION*
["_key":"Mf_Data":private]=>
string(3) "foo"
["_index":"Mf_Data":private]=>
int(0)
}
}
}
["_parent":"Mf_Data":private]=>
NULL
["_key":"Mf_Data":private]=>
NULL
["_index":"Mf_Data":private]=>
int(0)
}
Termo aditivo
1)
Portanto, esta é a toArray()
função que desenvolvi para a Mf_Data
classe:
public function toArray()
{
$array = (array) $this;
array_walk_recursive($array, function (&$property) {
if ($property instanceof Mf_Data) {
$property = $property->toArray();
}
});
return $array;
}
No entanto, como os Mf_Data
objetos também têm uma referência a seu objeto pai (que contém ), isso falha com a recursão. Funciona perfeitamente quando removo a _parent
referência.
2)
Apenas para acompanhar, a função final para transformar um objeto de nó de árvore complexo que eu escolhi foi:
// class name - Mf_Data
// exlcuded properties - $_parent, $_index
public function toArray()
{
$array = get_object_vars($this);
unset($array['_parent'], $array['_index']);
array_walk_recursive($array, function (&$property) {
if (is_object($property) && method_exists($property, 'toArray')) {
$property = $property->toArray();
}
});
return $array;
}
3)
Estou fazendo o acompanhamento novamente, com uma implementação um pouco mais limpa. Usar interfaces para uma instanceof
verificação parece muito mais limpo do que method_exists()
( no entanto method_exists()
, herança / implementação de corte cruzado ).
Usar unset()
parecia um pouco confuso também e parece que a lógica deveria ser refatorada em outro método. No entanto, esta implementação faz copiar a matriz de propriedade ( devido àarray_diff_key
), então algo a considerar.
interface ToMapInterface
{
function toMap();
function getToMapProperties();
}
class Node implements ToMapInterface
{
private $index;
private $parent;
private $values = array();
public function toMap()
{
$array = $this->getToMapProperties();
array_walk_recursive($array, function (&$value) {
if ($value instanceof ToMapInterface) {
$value = $value->toMap();
}
});
return $array;
}
public function getToMapProperties()
{
return array_diff_key(get_object_vars($this), array_flip(array(
'index', 'parent'
)));
}
}
fonte
JsonSerializable
Respostas:
editar : atualmente é 24/09/2016, e o PHP 5.4 foi lançado 01/03/2012 e o suporte terminou 01/09/2015. Ainda assim, essa resposta parece ganhar votos positivos. Se ainda estiver usando PHP <5.4, você está criando um risco de segurança e encerrando seu projeto . Se você não tem motivos convincentes para permanecer em <5.4, ou mesmo já usa a versão> = 5.4, não use esta resposta , e apenas use PHP> = 5.4 (ou, você sabe, um recente) e implemente a interface JsonSerializable
Você definiria uma função, por exemplo chamada
getJsonData();
, que retornaria um array,stdClass
objeto ou algum outro objeto com parâmetros visíveis em vez de parâmetros privados / protegidos, e faria ajson_encode($data->getJsonData());
. Em essência, implemente a função de 5.4, mas chame-a manualmente.Algo assim funcionaria, como
get_object_vars()
é chamado de dentro da classe, tendo acesso a variáveis privadas / protegidas:fonte
stdClass
? Estou pensando na direção de Reflexão , mas se não, vou apenas descobrir algo para executá-la recursivamente.getJsonData()
função, pode simplesmente chamarget_object_vars()
e percorrer esse resultado à procura de mais objetos._parent
propriedade para que a árvore possa ser percorrida até a raiz. Veja minha edição para uma atualização; talvez eu deva fazer outra pergunta, já que esse problema foi abstraído do meu original.unset($array['_parent']);
antes da caminhada deve resolver.$parent
como dados do usuário paraarray_walk_recursive()
. Simples é bonito! Além disso, é$array["\0class\0property"]
por causa da poluição de bytes nulos porque eu estava usando conversão. Acho que vou mudar paraget_object_vars()
.Nos casos mais simples, a sugestão de tipo deve funcionar:
fonte
json_encode()
irá codificar apenas variáveis de membros públicos. então, se você quiser incluir o privado uma vez, você deve fazer isso sozinho (como os outros sugeriram)fonte
Seguir o código está fazendo o trabalho usando reflexão. Ele assume que você tem getters para as propriedades que deseja serializar
fonte
Basta implementar uma interface fornecida pelo PHP JsonSerializable .
fonte
Como seu tipo de objeto é personalizado, eu tenderia a concordar com sua solução - dividi-lo em segmentos menores usando um método de codificação (como JSON ou serializar o conteúdo) e, por outro lado, ter o código correspondente para reconstruir o objeto.
fonte
Minha versão:
Implementação:
JsonUtils: GitHub
fonte
Tente usar isso, funcionou bem para mim.
fonte
Mude para seus tipos de variáveis
private
parapublic
Isso é simples e mais legível.
Por exemplo
Não está funcionando;
Está funcionando;
fonte
Fiz uma boa classe auxiliar que converte um objeto com métodos get em um array. Não depende de propriedades, apenas métodos.
Portanto, tenho o seguinte objeto de revisão que contém dois métodos:
Reveja
Comente
O script que escrevi irá transformá-lo em um array com propriedades parecidas com estas:
Fonte: PHP Serializer que converte um objeto em um array que pode ser codificado para JSON.
Tudo o que você precisa fazer é envolver json_encode em torno da saída.
Algumas informações sobre o script:
fonte
Passei algumas horas no mesmo problema. Meu objeto a ser convertido contém muitos outros cujas definições não devo tocar (API), então eu vim com uma solução que pode ser lenta, eu acho, mas estou usando para fins de desenvolvimento.
Este converte qualquer objeto em array
Isso converte qualquer objeto em stdClass
fonte
unlink($thisAnswer);