Więc byłem wędrówki php.net informacji na temat szeregowania PHP obiektów do JSON, gdy natknąłem się nowym interfejsem JsonSerializable . Jest to jednak tylko PHP> = 5.4 i pracuję w środowisku 5.3.x.
W jaki sposób osiągnięto taką funkcjonalność PHP <5.4 ?
Nie pracowałem jeszcze zbyt wiele z JSON, ale próbuję obsługiwać warstwę API w aplikacji i zrzucenie obiektu danych ( który w przeciwnym razie zostałby wysłany do widoku ) do JSON byłoby idealne.
Jeśli spróbuję bezpośrednio serializować obiekt, zwraca on pusty ciąg JSON; a to dlatego, że zakładam, json_encode()
że nie wie, co do cholery zrobić z obiektem. Powinienem rekurencyjnie zmniejszyć obiekt do tablicy, a następnie zakodować , że ?
Przykład
$data = new Mf_Data();
$data->foo->bar['hello'] = 'world';
echo json_encode($data)
tworzy pusty obiekt:
{}
var_dump($data)
jednak działa zgodnie z oczekiwaniami:
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)
}
Uzupełnienie
1)
Oto toArray()
funkcja, którą wymyśliłem dla Mf_Data
klasy:
public function toArray()
{
$array = (array) $this;
array_walk_recursive($array, function (&$property) {
if ($property instanceof Mf_Data) {
$property = $property->toArray();
}
});
return $array;
}
Jednak ponieważ Mf_Data
obiekty mają również odniesienie do ich obiektu nadrzędnego ( zawierającego ), kończy się to niepowodzeniem w przypadku rekursji. Działa jak urok, kiedy usuwam _parent
odniesienie.
2)
Aby kontynuować, ostatnią funkcją do przekształcenia złożonego obiektu z węzłem drzewa, z którym poszedłem, było:
// 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)
Kontynuuję ponownie, z nieco czystszą implementacją. Używanie interfejsów do instanceof
sprawdzenia wydaje się znacznie czystsze niż method_exists()
( jednak method_exists()
dziedziczenie / implementacja krzyżowa ).
Używanie również unset()
wydawało się nieco kłopotliwe i wydaje się, że logikę należy przełożyć na inną metodę. Jednak ta implementacja ma skopiować tablicę posesji ( z powoduarray_diff_key
), więc coś do rozważenia.
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'
)));
}
}
źródło
JsonSerializable
Odpowiedzi:
edycja : obecnie jest 2016-09-24, a PHP 5.4 zostało wydane 2012-03-01, a wsparcie zakończyło się 2015-09-01. Wydaje się jednak, że ta odpowiedź zyskuje uznanie. Jeśli nadal używasz PHP <5.4, stwarzasz zagrożenie bezpieczeństwa i zagrażasz projektowi . Jeśli nie masz przekonujących powodów, aby pozostać przy <5.4, a nawet już używasz wersji> = 5.4, nie używaj tej odpowiedzi i po prostu użyj PHP> = 5.4 (lub, wiesz, najnowszego) i zaimplementuj interfejs JsonSerializable
Zdefiniowałbyś funkcję, na przykład nazwaną
getJsonData();
, która zwróciłaby tablicę,stdClass
obiekt lub inny obiekt z widocznymi parametrami, a nie prywatnymi / chronionymi, i zrobiłby ajson_encode($data->getJsonData());
. Zasadniczo zaimplementuj funkcję z 5.4, ale wywołaj ją ręcznie.Coś takiego zadziałałoby, jak
get_object_vars()
jest wywoływane z wnętrza klasy, mając dostęp do prywatnych / chronionych zmiennych:źródło
stdClass
? Myślę w kierunku Odbicia , ale jeśli nie, po prostu wymyślę coś, aby wykonać to rekurencyjnie.getJsonData()
funkcji, możesz po prostu wywołaćget_object_vars()
i przejrzeć ten wynik, szukając więcej obiektów._parent
właściwość, dzięki czemu drzewo można przejść do katalogu głównego. Zobacz moją edycję dla aktualizacji; być może powinienem zadać inne pytanie, ponieważ ta kwestia jest teraz oderwana od mojego oryginału.unset($array['_parent']);
przed spacer powinien załatwić sprawę.$parent
jako dane użytkownikaarray_walk_recursive()
. Prostota jest piękna! Poza tym jest to$array["\0class\0property"]
spowodowane zanieczyszczeniem zerobajtowym, ponieważ używałem odlewania. Myślę, że przestawię się naget_object_vars()
.W najprostszych przypadkach podpowiedź typu powinna działać:
źródło
json_encode()
zakoduje tylko publiczne zmienne składowe. więc jeśli chcesz dołączyć prywatny, gdy musisz to zrobić sam (jak sugerowali inni)źródło
Poniższy kod wykonuje zadanie za pomocą refleksji. Zakłada się, że masz metody pobierające dla właściwości, które chcesz serializować
źródło
Po prostu zaimplementuj interfejs podany przez PHP JsonSerializable .
źródło
Ponieważ typ twojego obiektu jest niestandardowy, zwykle zgadzam się z twoim rozwiązaniem - podziel je na mniejsze segmenty za pomocą metody kodowania (takiej jak JSON lub serializacja treści), a na drugim końcu mam odpowiedni kod, aby ponownie skonstruować obiekt.
źródło
Moja wersja:
Realizacja:
JsonUtils: GitHub
źródło
Spróbuj tego użyć, to zadziałało dobrze dla mnie.
źródło
Zmień typy zmiennych
private
napublic
To jest proste i bardziej czytelne.
Na przykład
Nie działa;
To działa;
źródło
Zrobiłem ładną klasę pomocniczą, która konwertuje obiekt za pomocą metod get na tablicę. Nie opiera się na właściwościach, tylko na metodach.
Mam więc następujący obiekt przeglądu, który zawiera dwie metody:
Przejrzeć
Komentarz
Napisany przeze mnie skrypt przekształci go w tablicę z właściwościami, które wyglądają następująco:
Źródło: serializator PHP, który konwertuje obiekt na tablicę, którą można zakodować do formatu JSON.
Wszystko, co musisz zrobić, to owinąć dane wyjściowe json_encode.
Kilka informacji o skrypcie:
źródło
Spędziłem kilka godzin nad tym samym problemem. Mój obiekt do konwersji zawiera wiele innych, których definicji nie powinienem dotykać (API), więc wymyśliłem rozwiązanie, które może być powolne, ale używam go do celów programistycznych.
Ten konwertuje dowolny obiekt na tablicę
To konwertuje dowolny obiekt na stdClass
źródło
unlink($thisAnswer);
inline php strings
,eval
,shell_exec(php)
... cc-kombi.