Lekcja 19: JSON - Praca z Danymi w Formacie JSON
Witaj w dziewiętnastej lekcji kursu PHP! W dzisiejszym świecie aplikacji internetowych wymiana danych między różnymi systemami i technologiami jest codziennością. Jednym z najpopularniejszych formatów używanych do tego celu jest JSON (JavaScript Object Notation). Jest to lekki, tekstowy format wymiany danych, czytelny zarówno dla ludzi, jak i łatwy do parsowania przez maszyny. PHP oferuje wbudowane, wydajne funkcje do pracy z JSON, które pozwalają na łatwe kodowanie danych PHP do formatu JSON oraz dekodowanie danych JSON na zmienne PHP. W tej lekcji dokładnie przyjrzymy się formatowi JSON, jego składni oraz sposobom jego obsługi w PHP.
Co to jest JSON?
JSON, czyli JavaScript Object Notation, został pierwotnie wywiedziony z języka JavaScript (konkretnie ze sposobu zapisu literałów obiektów i tablic w JavaScript), ale obecnie jest formatem niezależnym od języka programowania. Jego prostota, czytelność i łatwość implementacji parserów sprawiły, że stał się de facto standardem w wielu obszarach, szczególnie w komunikacji z API webowymi (REST API).
Kluczowe cechy JSON:
- Tekstowy format: Dane JSON są reprezentowane jako zwykły tekst, co ułatwia ich przesyłanie i przechowywanie.
- Czytelny dla człowieka: Składnia JSON jest stosunkowo prosta i przypomina strukturę danych znaną z wielu języków programowania.
- Łatwy do parsowania przez maszyny: Większość języków programowania, w tym PHP, posiada wbudowane biblioteki do efektywnego parsowania i generowania JSON.
- Niezależny od języka: Chociaż nazwa sugeruje JavaScript, JSON jest uniwersalnym formatem wymiany danych.
- Lekki: W porównaniu do innych formatów, takich jak XML, JSON jest zazwyczaj bardziej zwięzły, co oznacza mniejszy narzut danych przy transmisji.
Podstawowa Składnia JSON
JSON opiera się na dwóch podstawowych strukturach:
- Kolekcja par nazwa/wartość (Obiekt): Jest to nieuporządkowany zbiór par klucz-wartość. W JSON obiekt jest otoczony nawiasami klamrowymi
{}
. Klucze muszą być stringami (ujęte w podwójne cudzysłowy), a wartości mogą być dowolnego typu JSON. Pary klucz-wartość są oddzielone przecinkami, a klucz od wartości dwukropkiem. Odpowiada to obiektom w JavaScript lub tablicom asocjacyjnym w PHP. - Uporządkowana lista wartości (Tablica): Jest to uporządkowana sekwencja wartości. W JSON tablica jest otoczona nawiasami kwadratowymi
[]
. Wartości są oddzielone przecinkami i mogą być dowolnego typu JSON. Odpowiada to tablicom indeksowanym w PHP lub tablicom w JavaScript.
Typy Danych w JSON:
- String (Ciąg znaków): Sekwencja znaków Unicode, ujęta w podwójne cudzysłowy (
" "
). Znaki specjalne, takie jak cudzysłów, backslash, muszą być poprzedzone znakiem ucieczki (np.\"
,\\
). - Number (Liczba): Liczba całkowita lub zmiennoprzecinkowa. Nie jest ujmowana w cudzysłowy. (np.
123
,-42
,3.14159
,1.2e+10
). - Boolean (Wartość logiczna): Może przyjmować wartość
true
lubfalse
(bez cudzysłowów). - Array (Tablica): Uporządkowana lista wartości, ujęta w
[]
. - Object (Obiekt): Nieuporządkowana kolekcja par klucz-wartość, ujęta w
{}
. null
: Reprezentuje pustą wartość (bez cudzysłowów).
Przykład struktury JSON:
{
"imie": "Jan",
"nazwisko": "Kowalski",
"wiek": 30,
"czyAktywny": true,
"adres": {
"ulica": "Kwiatowa",
"numerDomu": "10A",
"miasto": "Warszawa",
"kodPocztowy": "01-234"
},
"jezyki": [
"polski",
"angielski"
],
"ostatnieLogowanie": null
}
W powyższym przykładzie widzimy obiekt główny z kluczami takimi jak "imie", "nazwisko", "adres" (którego wartością jest kolejny obiekt), "jezyki" (którego wartością jest tablica stringów) oraz "ostatnieLogowanie" z wartością null
.
Praca z JSON w PHP
PHP dostarcza dwie główne funkcje do pracy z JSON, dostępne od PHP 5.2.0, które są częścią domyślnej konfiguracji PHP (nie wymagają instalacji dodatkowych rozszerzeń, chyba że PHP zostało skompilowane z opcją --disable-json
).
Kodowanie Danych PHP do JSON - Funkcja json_encode()
Funkcja json_encode()
służy do konwersji zmiennej PHP (najczęściej tablicy lub obiektu) na jej reprezentację w formacie JSON (string).
Składnia: string|false json_encode(mixed $value, int $flags = 0, int $depth = 512)
$value
: Wartość PHP do zakodowania. Może to być dowolny typ danych z wyjątkiem zasobów (resource). Wszystkie stringi muszą być zakodowane w UTF-8.$flags
(opcjonalny): Maska bitowa składająca się z różnych stałych, które modyfikują sposób kodowania. Najważniejsze z nich to:JSON_HEX_TAG
: Wszystkie znaki<
i>
są konwertowane na\u003C
i\u003E
. Użyteczne, gdy JSON ma być osadzony w HTML.JSON_HEX_AMP
: Wszystkie znaki&
są konwertowane na\u0026
.JSON_HEX_APOS
: Wszystkie znaki'
(apostrof) są konwertowane na\u0027
.JSON_HEX_QUOT
: Wszystkie znaki"
(cudzysłów) są konwertowane na\u0022
.JSON_FORCE_OBJECT
: Wymusza, aby wyjściem był obiekt JSON ({}
) nawet jeśli wejściem jest pusta tablica lub tablica indeksowana (która normalnie zostałaby zakodowana jako tablica JSON[]
).JSON_NUMERIC_CHECK
: Koduje numeryczne stringi jako liczby. (Uwaga: może prowadzić do utraty danych, jeśli string nie jest poprawną liczbą lub jest zbyt duży).JSON_PRETTY_PRINT
(od PHP 5.4.0): Formatuje wyjściowy JSON w sposób czytelny dla człowieka, dodając wcięcia i nowe linie. Bardzo przydatne do debugowania.JSON_UNESCAPED_SLASHES
(od PHP 5.4.0): Nie poprzedza ukośników (/
) znakiem ucieczki (\
).JSON_UNESCAPED_UNICODE
(od PHP 5.4.0): Koduje wielobajtowe znaki Unicode bezpośrednio (np. "zażółć gęślą jaźń") zamiast jako sekwencje\uXXXX
. Wymaga, aby dane wejściowe były w UTF-8.JSON_PARTIAL_OUTPUT_ON_ERROR
(od PHP 5.5.0): Jeśli wystąpi błąd podczas kodowania (np. nieobsługiwany typ), próbuje zakodować część danych, która jest poprawna, zamiast zwracaćfalse
.JSON_PRESERVE_ZERO_FRACTION
(od PHP 5.6.6): Zapewnia, że liczby zmiennoprzecinkowe będą zawsze kodowane jako liczby zmiennoprzecinkowe, nawet jeśli część ułamkowa wynosi zero (np.1.0
zamiast1
).JSON_THROW_ON_ERROR
(od PHP 7.3.0): Zamiast zwracaćfalse
i ustawiać błąd globalny (json_last_error()
), rzuca wyjątekJsonException
w przypadku błędu. To preferowany sposób obsługi błędów w nowoczesnym PHP.
$depth
(opcjonalny, od PHP 5.3.0): Maksymalna głębokość zagnieżdżenia struktur danych do zakodowania. Domyślnie 512.
Funkcja zwraca string JSON w przypadku sukcesu lub false
w przypadku błędu (chyba że użyto JSON_THROW_ON_ERROR
).
<?php
// Przykład 1: Prosta tablica asocjacyjna
$dane_uzytkownika_php = [
"id" => 101,
"imie" => "Anna",
"email" => "anna.nowak@example.com",
"tagi" => ["php", "webdev", "kurs"]
];
$json_string = json_encode($dane_uzytkownika_php);
echo "<h3>Prosta tablica asocjacyjna:</h3>";
echo "<pre>" . htmlspecialchars($json_string) . "</pre>";
// Wynik: {"id":101,"imie":"Anna","email":"anna.nowak@example.com","tagi":["php","webdev","kurs"]}
// Przykład 2: Z flagą JSON_PRETTY_PRINT
$json_pretty_string = json_encode($dane_uzytkownika_php, JSON_PRETTY_PRINT);
echo "<h3>Z JSON_PRETTY_PRINT:</h3>";
echo "<pre>" . htmlspecialchars($json_pretty_string) . "</pre>";
/* Wynik:
{
"id": 101,
"imie": "Anna",
"email": "anna.nowak@example.com",
"tagi": [
"php",
"webdev",
"kurs"
]
}
*/
// Przykład 3: Polskie znaki i JSON_UNESCAPED_UNICODE
$dane_polskie = [
"miasto" => "Łódź",
"opis" => "Zażółć gęślą jaźń"
];
$json_polskie_escaped = json_encode($dane_polskie, JSON_PRETTY_PRINT);
echo "<h3>Polskie znaki (domyślnie escaped):</h3>";
echo "<pre>" . htmlspecialchars($json_polskie_escaped) . "</pre>";
/* Wynik:
{
"miasto": "\u0141\u00f3d\u017a",
"opis": "Za\u017c\u00f3\u0142\u0107 g\u0119\u015bl\u0105 ja\u017a\u0144"
}
*/
$json_polskie_unescaped = json_encode($dane_polskie, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
echo "<h3>Polskie znaki (z JSON_UNESCAPED_UNICODE):</h3>";
echo "<pre>" . htmlspecialchars($json_polskie_unescaped) . "</pre>";
/* Wynik:
{
"miasto": "Łódź",
"opis": "Zażółć gęślą jaźń"
}
*/
// Przykład 4: Kodowanie obiektu PHP
class Produkt {
public $nazwa;
public $cena;
private $id_wewnetrzne; // Prywatne właściwości nie są domyślnie kodowane
public function __construct($nazwa, $cena, $id_wewnetrzne) {
$this->nazwa = $nazwa;
$this->cena = $cena;
$this->id_wewnetrzne = $id_wewnetrzne;
}
}
$produkt_obj = new Produkt("Super Gadżet", 79.99, "XYZ123");
$json_obiekt = json_encode($produkt_obj, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
echo "<h3>Kodowanie obiektu PHP:</h3>";
echo "<pre>" . htmlspecialchars($json_obiekt) . "</pre>";
// Wynik (tylko publiczne właściwości):
// {
// "nazwa": "Super Gadżet",
// "cena": 79.99
// }
// Aby zakodować również prywatne/chronione właściwości, obiekt musi implementować interfejs JsonSerializable
// lub można użyć sztuczki z konwersją na tablicę (ale to nie zawsze idealne).
// Przykład 5: Obsługa błędów z JSON_THROW_ON_ERROR (PHP >= 7.3)
$niepoprawne_dane_utf8 = "\xB1\x31"; // Niepoprawny ciąg UTF-8
try {
$json_error = json_encode($niepoprawne_dane_utf8, JSON_THROW_ON_ERROR);
echo $json_error;
} catch (JsonException $e) {
echo "<h3>Błąd kodowania JSON (JsonException):</h3>";
echo "Wiadomość: " . $e->getMessage() . "<br>"; // Np. "Malformed UTF-8 characters, possibly incorrectly encoded"
echo "Kod: " . $e->getCode() . "<br>";
}
?>
Dekodowanie Danych JSON do PHP - Funkcja json_decode()
Funkcja json_decode()
służy do konwersji stringa JSON na zmienną PHP (domyślnie obiekt typu stdClass
, lub tablicę asocjacyjną, jeśli podano odpowiednią opcję).
Składnia: mixed json_decode(string $json, ?bool $associative = null, int $depth = 512, int $flags = 0)
$json
: String JSON do zdekodowania. Musi być poprawnie zakodowany w UTF-8.$associative
(opcjonalny): Wartość logiczna. Jeślitrue
, obiekty JSON będą konwertowane na tablice asocjacyjne PHP. Jeślifalse
(domyślnie) lubnull
, będą konwertowane na obiektystdClass
.$depth
(opcjonalny): Maksymalna głębokość zagnieżdżenia struktury JSON do zdekodowania. Domyślnie 512.$flags
(opcjonalny): Maska bitowa. Najważniejsze stałe:JSON_BIGINT_AS_STRING
: Dekoduje duże liczby całkowite jako stringi zamiast liczb zmiennoprzecinkowych (co mogłoby prowadzić do utraty precyzji).JSON_OBJECT_AS_ARRAY
: To samo co ustawienie$associative
natrue
.JSON_THROW_ON_ERROR
(od PHP 7.3.0): Rzuca wyjątekJsonException
w przypadku błędu dekodowania. Preferowany sposób obsługi błędów.
Funkcja zwraca zdekodowaną wartość PHP (obiekt, tablicę, string, liczbę, boolean lub null
) w przypadku sukcesu, lub null
w przypadku błędu (chyba że użyto JSON_THROW_ON_ERROR
). Uwaga: null
może być również poprawną wartością JSON, więc do sprawdzania błędów należy używać json_last_error()
(lub wyjątków).
<?php
$json_data_string =
'{ "id": 205, "produkt": "Książka PHP", "cena": 99.50, "dostepny": true, "autor": { "imie": "Cezary", "nazwisko": "PHPowiec" }, "tagi": ["programowanie", "php", "web"] }';
// Przykład 1: Dekodowanie do obiektu stdClass (domyślnie)
$dane_php_obj = json_decode($json_data_string);
echo "<h3>Dekodowanie do obiektu stdClass:</h3>";
if ($dane_php_obj !== null) {
echo "ID Produktu: " . htmlspecialchars($dane_php_obj->id) . "<br>";
echo "Nazwa Produktu: " . htmlspecialchars($dane_php_obj->produkt) . "<br>";
echo "Cena: " . htmlspecialchars($dane_php_obj->cena) . "<br>";
echo "Dostępny: " . ($dane_php_obj->dostepny ? "Tak" : "Nie") . "<br>";
echo "Autor: " . htmlspecialchars($dane_php_obj->autor->imie) . " " . htmlspecialchars($dane_php_obj->autor->nazwisko) . "<br>";
echo "Tagi: " . htmlspecialchars(implode(", ", $dane_php_obj->tagi)) . "<br>";
} else {
echo "Błąd dekodowania JSON!<br>";
}
// Przykład 2: Dekodowanie do tablicy asocjacyjnej
$dane_php_array = json_decode($json_data_string, true); // lub $associative = true
echo "<h3>Dekodowanie do tablicy asocjacyjnej:</h3>";
if ($dane_php_array !== null) {
echo "ID Produktu: " . htmlspecialchars($dane_php_array["id"]) . "<br>";
echo "Nazwa Produktu: " . htmlspecialchars($dane_php_array["produkt"]) . "<br>";
echo "Cena: " . htmlspecialchars($dane_php_array["cena"]) . "<br>";
echo "Dostępny: " . ($dane_php_array["dostepny"] ? "Tak" : "Nie") . "<br>";
echo "Autor: " . htmlspecialchars($dane_php_array["autor"]["imie"]) . " " . htmlspecialchars($dane_php_array["autor"]["nazwisko"]) . "<br>";
echo "Tagi: " . htmlspecialchars(implode(", ", $dane_php_array["tagi"])) . "<br>";
} else {
echo "Błąd dekodowania JSON!<br>";
}
// Przykład 3: Obsługa błędów dekodowania (PHP >= 7.3 z JSON_THROW_ON_ERROR)
$niepoprawny_json_string = '{ "nazwa": "Test", "wiek: 30 }'; // Brak cudzysłowu przy kluczu wiek
try {
$wynik = json_decode($niepoprawny_json_string, false, 512, JSON_THROW_ON_ERROR);
// var_dump($wynik);
} catch (JsonException $e) {
echo "<h3>Błąd dekodowania JSON (JsonException):</h3>";
echo "Wiadomość: " . $e->getMessage() . "<br>"; // Np. "Syntax error"
echo "Kod: " . $e->getCode() . "<br>";
}
?>
Obsługa Błędów JSON (dla PHP < 7.3 lub bez JSON_THROW_ON_ERROR
)
Jeśli nie używasz JSON_THROW_ON_ERROR
, musisz ręcznie sprawdzać błędy po wywołaniu json_encode()
lub json_decode()
. Służą do tego funkcje:
json_last_error()
: Zwraca kod ostatniego błędu, który wystąpił podczas ostatniego wywołania funkcji JSON. ZwracaJSON_ERROR_NONE
(wartość 0), jeśli nie było błędu.json_last_error_msg()
(od PHP 5.5.0): Zwraca czytelny dla człowieka komunikat o ostatnim błędzie.
Możliwe kody błędów (stałe JSON_ERROR_*
):
JSON_ERROR_NONE
: Brak błędu.JSON_ERROR_DEPTH
: Osiągnięto maksymalną głębokość stosu.JSON_ERROR_STATE_MISMATCH
: Nieprawidłowy lub źle sformatowany JSON (np. niedomknięte nawiasy).JSON_ERROR_CTRL_CHAR
: Znaleziono nieoczekiwany znak kontrolny.JSON_ERROR_SYNTAX
: Błąd składni.JSON_ERROR_UTF8
: Niepoprawnie zakodowane znaki UTF-8, prawdopodobnie błąd kodowania.JSON_ERROR_RECURSION
(od PHP 5.5.0): Wykryto rekurencję w wartości przekazanej dojson_encode()
.JSON_ERROR_INF_OR_NAN
(od PHP 5.5.0): Wykryto wartośćINF
lubNAN
w wartości przekazanej dojson_encode()
.JSON_ERROR_UNSUPPORTED_TYPE
(od PHP 5.5.0): Przekazano nieobsługiwany typ danych dojson_encode()
(np. zasób).- ... i inne, bardziej specyficzne błędy.
<?php
$bledny_json = "{ 'klucz': 'wartość' }"; // Użyto apostrofów zamiast cudzysłowów - błąd składni JSON
$dane = json_decode($bledny_json);
if ($dane === null && json_last_error() !== JSON_ERROR_NONE) {
echo "<h3>Wystąpił błąd podczas dekodowania JSON:</h3>";
echo "Kod błędu: " . json_last_error() . "<br>";
if (function_exists('json_last_error_msg')) { // json_last_error_msg() od PHP 5.5
echo "Komunikat błędu: " . json_last_error_msg() . "<br>";
}
// Dla $bledny_json powyżej, błędem będzie JSON_ERROR_SYNTAX
} elseif ($dane === null) {
echo "Zdekodowano poprawnie, ale wynikiem jest null.<br>";
} else {
echo "<h3>Dane zdekodowane pomyślnie (sposób tradycyjny):</h3>";
// var_dump($dane);
}
?>
Używanie JSON_THROW_ON_ERROR
z blokami try-catch
jest jednak znacznie czystszym i nowocześniejszym podejściem do obsługi błędów JSON w PHP 7.3+.
Praktyczne Zastosowania JSON w PHP
- Komunikacja z API Webowymi (REST API): Wiele API (np. pogodowe, mapowe, social media) zwraca dane w formacie JSON. PHP może łatwo pobrać te dane (np. za pomocą cURL lub funkcji
file_get_contents()
z odpowiednimi ustawieniami strumienia) i zdekodować je za pomocąjson_decode()
. - Wysyłanie Danych do API: Podobnie, jeśli API oczekuje danych w formacie JSON w ciele żądania (np. POST, PUT), PHP może zakodować tablicę lub obiekt do JSON za pomocą
json_encode()
i wysłać. - Konfiguracja Aplikacji: Pliki konfiguracyjne mogą być przechowywane w formacie JSON ze względu na jego czytelność i łatwość parsowania.
- Przechowywanie Danych w Bazach Danych NoSQL: Wiele baz danych NoSQL (np. MongoDB) używa formatu BSON (binarny JSON) lub bezpośrednio JSON do przechowywania dokumentów. PHP może łatwo przygotować dane w tym formacie. Nawet relacyjne bazy danych (np. MySQL, PostgreSQL) oferują typy JSON do przechowywania struktur JSON w kolumnach.
- Wymiana Danych z JavaScript po Stronie Klienta (AJAX): JSON jest naturalnym formatem do wymiany danych między PHP (backend) a JavaScript (frontend) w żądaniach AJAX. PHP może generować JSON, który jest następnie łatwo przetwarzany przez JavaScript.
<?php
// Przykład: Pobieranie danych z prostego publicznego API (JSONPlaceholder)
$url_api = "https://jsonplaceholder.typicode.com/users/1";
// Użycie file_get_contents (dla prostych GET, wymaga allow_url_fopen=On w php.ini)
// W produkcji lepiej użyć cURL dla większej kontroli i obsługi błędów.
$json_response = @file_get_contents($url_api);
if ($json_response === false) {
echo "Nie udało się pobrać danych z API.<br>";
} else {
try {
$user_data = json_decode($json_response, true, 512, JSON_THROW_ON_ERROR);
echo "<h3>Dane użytkownika z API:</h3>";
echo "Imię: " . htmlspecialchars($user_data["name"]) . "<br>";
echo "Email: " . htmlspecialchars($user_data["email"]) . "<br>";
echo "Miasto: " . htmlspecialchars($user_data["address"]["city"]) . "<br>";
} catch (JsonException $e) {
echo "Błąd dekodowania odpowiedzi JSON z API: " . $e->getMessage() . "<br>";
}
}
// Przykład: Generowanie JSON dla odpowiedzi AJAX
// header('Content-Type: application/json; charset=utf-8'); // Ważny nagłówek!
$odpowiedz_ajax = [
"status" => "success",
"wiadomosc" => "Operacja zakończona pomyślnie!",
"dane" => ["id_rekordu" => 42, "nowa_wartosc" => "Zaktualizowano"]
];
// echo json_encode($odpowiedz_ajax, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
// exit;
?>
Bezpieczeństwo i Dobre Praktyki
- Walidacja Danych Wejściowych: Zawsze waliduj dane otrzymane w formacie JSON z zewnętrznych źródeł (np. od użytkownika, z API). Nie ufaj, że struktura i typy będą zgodne z oczekiwaniami. Sprawdzaj istnienie kluczy, typy wartości, zakresy itp.
- Oczyszczanie Danych Wyjściowych (Sanitization): Jeśli dane z JSON mają być wyświetlone w HTML, zawsze je oczyszczaj (np. za pomocą
htmlspecialchars()
), aby zapobiec atakom XSS. - Używaj
JSON_THROW_ON_ERROR
: W PHP 7.3+ jest to preferowany sposób obsługi błędów kodowania/dekodowania JSON, ponieważ pozwala na użycie standardowych mechanizmów wyjątków. - Ustawiaj Nagłówek
Content-Type
: Gdy serwujesz JSON jako odpowiedź HTTP (np. dla AJAX lub API), ustawiaj poprawny nagłówek:header('Content-Type: application/json; charset=utf-8');
. - Kodowanie UTF-8: Upewnij się, że wszystkie stringi przekazywane do
json_encode()
są w kodowaniu UTF-8. Podobnie, string JSON przekazywany dojson_decode()
powinien być w UTF-8. UżywajJSON_UNESCAPED_UNICODE
dla lepszej czytelności JSON z polskimi znakami. - Głębokość Rekursji (
$depth
): Bądź świadomy limitu głębokości przy kodowaniu i dekodowaniu, aby uniknąć błędówJSON_ERROR_DEPTH
przy bardzo zagnieżdżonych strukturach. - Prywatne Właściwości Obiektów: Pamiętaj, że
json_encode()
domyślnie koduje tylko publiczne właściwości obiektów. Aby kontrolować serializację, obiekt może implementować interfejsJsonSerializable
i jego metodęjsonSerialize()
.
Podsumowanie Lekcji
JSON jest niezwykle ważnym formatem wymiany danych we współczesnym programowaniu webowym. PHP dostarcza prostych, ale potężnych funkcji json_encode()
i json_decode()
, które umożliwiają efektywną pracę z tym formatem. Zrozumienie składni JSON, opcji dostępnych w funkcjach PHP oraz zasad bezpieczeństwa jest kluczowe dla każdego dewelopera PHP. Umiejętność kodowania tablic i obiektów PHP do JSON oraz dekodowania stringów JSON na struktury danych PHP otwiera drzwi do integracji z licznymi API i efektywnej komunikacji z aplikacjami klienckimi.
W następnej lekcji podsumujemy dotychczas zdobytą wiedzę z podstaw PHP, przygotowując się do bardziej zaawansowanych tematów.
Zadanie praktyczne
Stwórz skrypt PHP, który:
- Definiuje tablicę asocjacyjną PHP reprezentującą informacje o książce: tytuł, autor (jako kolejna tablica asocjacyjna z imieniem i nazwiskiem), rok wydania (liczba), ISBN (string) oraz listę tagów (tablica indeksowana stringów). Użyj polskich znaków w tytule i autorze.
- Koduje tę tablicę do formatu JSON, używając opcji
JSON_PRETTY_PRINT
orazJSON_UNESCAPED_UNICODE
. Wyświetl wynikowy string JSON (użyjhtmlspecialchars()
do wyświetlenia w HTML). - Tworzy string JSON ręcznie (jako tekst), który zawiera błąd składniowy (np. brakujący przecinek lub cudzysłów).
- Próbuje zdekodować ten błędny string JSON używając
json_decode()
z opcjąJSON_THROW_ON_ERROR
w blokutry-catch
. Wyświetl komunikat o błędzie, jeśli wystąpi. - Próbuje zdekodować poprawny string JSON (ten wygenerowany w punkcie 2) z powrotem na tablicę asocjacyjną PHP. Wyświetl tytuł i imię autora z odkodowanej tablicy.
Pokaż przykładowe rozwiązanie
<?php
// 1. Definicja tablicy PHP z informacjami o książce
$ksiazka_php = [
"tytul" => "Pan Tadeusz, czyli ostatni zajazd na Litwie",
"autor" => [
"imie" => "Adam",
"nazwisko" => "Mickiewicz"
],
"rokWydania" => 1834,
"isbn" => "978-83-7779-590-1",
"tagi" => ["epopeja narodowa", "romantyzm", "poemat", "lektura szkolna"]
];
echo "<h3>1. Dane książki w PHP:</h3>";
echo "<pre>";
print_r($ksiazka_php);
echo "</pre>";
// 2. Kodowanie do JSON z opcjami
$json_ksiazka = json_encode($ksiazka_php, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR);
echo "<h3>2. Zakodowany JSON:</h3>";
echo "<pre>" . htmlspecialchars($json_ksiazka) . "</pre>";
// 3. Błędny string JSON
$bledny_json_string = '{ "tytul": "Błędna Książka", "autor": "Nieznany" "rok": 2023 }'; // Brak przecinka po "Nieznany"
echo "<h3>4. Próba dekodowania błędnego JSON:</h3>";
try {
$zdekodowany_bledny = json_decode($bledny_json_string, true, 512, JSON_THROW_ON_ERROR);
echo "<p>Błędny JSON został (niespodziewanie) zdekodowany:</p>";
echo "<pre>";
print_r($zdekodowany_bledny);
echo "</pre>";
} catch (JsonException $e) {
echo "<p style='color:red;'>Wystąpił błąd podczas dekodowania błędnego JSON:<br>";
echo "Komunikat: " . htmlspecialchars($e->getMessage()) . "<br>";
echo "Kod: " . htmlspecialchars($e->getCode()) . "</p>";
}
// 5. Dekodowanie poprawnego JSON z powrotem do tablicy PHP
echo "<h3>5. Dekodowanie poprawnego JSON do tablicy PHP:</h3>";
try {
$ksiazka_zdekodowana_php = json_decode($json_ksiazka, true, 512, JSON_THROW_ON_ERROR);
echo "<p>Tytuł: " . htmlspecialchars($ksiazka_zdekodowana_php["tytul"]) . "</p>";
echo "<p>Autor: " . htmlspecialchars($ksiazka_zdekodowana_php["autor"]["imie"]) . " " . htmlspecialchars($ksiazka_zdekodowana_php["autor"]["nazwisko"]) . "</p>";
} catch (JsonException $e) {
echo "<p style='color:red;'>Wystąpił błąd podczas dekodowania poprawnego JSON:<br>";
echo "Komunikat: " . htmlspecialchars($e->getMessage()) . "<br>";
echo "Kod: " . htmlspecialchars($e->getCode()) . "</p>";
}
?>
Zadanie do samodzielnego wykonania
Napisz skrypt, który pobiera dane o losowym użytkowniku z publicznego API https://randomuser.me/api/
. API to zwraca dane w formacie JSON.
- Użyj
file_get_contents()
(lub cURL, jeśli wolisz) do pobrania danych z API. - Zdekoduj odpowiedź JSON do tablicy asocjacyjnej PHP. Pamiętaj o obsłudze błędów (zarówno pobierania, jak i dekodowania JSON).
- Wyświetl następujące informacje o użytkowniku: imię, nazwisko, płeć, adres email oraz pełny adres (ulica, miasto, kraj).
- Stwórz nową tablicę PHP zawierającą tylko wybrane przez Ciebie informacje (np. imię, nazwisko, email, zdjęcie-thumbnail). Zakoduj tę nową tablicę do formatu JSON z opcją
JSON_PRETTY_PRINT
i wyświetl wynik.
FAQ - Praca z JSON w PHP
Czy JSON jest lepszy niż XML?
JSON jest często preferowany nad XML w kontekście API webowych ze względu na mniejszą rozwlekłość, prostszą składnię i lepsze dopasowanie do struktur danych w JavaScript. XML nadal ma swoje zastosowania, szczególnie w systemach korporacyjnych, dokumentach i tam, gdzie wymagane są schematy (XSD) czy transformacje (XSLT).
Jak obsłużyć bardzo duże pliki JSON w PHP?
json_decode()
wczytuje cały string JSON do pamięci. Dla bardzo dużych plików JSON, które nie mieszczą się w pamięci, potrzebne są techniki strumieniowego parsowania. Można użyć bibliotek takich jak JSON Machine
lub salsify/jsonstreamingparser
, które pozwalają przetwarzać JSON fragment po fragmencie.
Co jeśli mój string JSON nie jest w UTF-8?
Funkcje JSON w PHP oczekują stringów w UTF-8. Jeśli masz dane w innym kodowaniu (np. ISO-8859-2, Windows-1250), musisz je najpierw przekonwertować na UTF-8, np. za pomocą funkcji mb_convert_encoding()
lub iconv()
, przed przekazaniem do json_encode()
lub json_decode()
.
Czy mogę przechowywać komentarze w pliku JSON?
Standard JSON nie dopuszcza komentarzy. Jeśli potrzebujesz komentarzy w pliku konfiguracyjnym, rozważ użycie formatu JSONC (JSON with Comments) i odpowiedniego parsera, lub innego formatu jak YAML, który natywnie wspiera komentarze.
Jak przekształcić obiekt PHP na JSON, włączając prywatne właściwości?
Najlepszym sposobem jest zaimplementowanie interfejsu JsonSerializable
w klasie obiektu. Metoda jsonSerialize()
tej klasy musi zwrócić dane, które mają być zserializowane przez json_encode()
. W tej metodzie masz pełną kontrolę nad tym, które właściwości (publiczne, prywatne, chronione) i w jakiej formie zostaną uwzględnione.
Czy json_decode(..., true)
zawsze jest lepsze niż dekodowanie do obiektu?
To zależy od preferencji i kontekstu. Praca z tablicami asocjacyjnymi ($assoc = true
) jest często bardziej naturalna dla programistów PHP przyzwyczajonych do tablic. Obiekty stdClass
mogą być nieco bardziej wydajne w niektórych przypadkach i są bliższe oryginalnej koncepcji JSON jako notacji obiektowej. Wybór zależy od stylu kodowania i wymagań projektu.
Co oznacza opcja JSON_NUMERIC_CHECK
w json_encode()
?
Ta opcja próbuje automatycznie przekonwertować stringi zawierające liczby na typy numeryczne w wynikowym JSON. Należy jej używać ostrożnie, ponieważ może prowadzić do nieoczekiwanych rezultatów lub utraty danych, jeśli string nie jest poprawną liczbą lub reprezentuje np. numer telefonu z wiodącymi zerami, który nie powinien być traktowany jako liczba.