JSON и XML в PHP
JSON (JavaScript Object Notation)
json_encode — кодирование в JSON
<?php
declare(strict_types=1);
// Basic encoding
$data = ['name' => 'Alice', 'age' => 25, 'active' => true];
$json = json_encode($data);
echo $json; // {"name":"Alice","age":25,"active":true}
// Pretty print
$json = json_encode($data, JSON_PRETTY_PRINT);
/*
{
"name": "Alice",
"age": 25,
"active": true
}
*/
// Common flags
$json = json_encode($data,
JSON_PRETTY_PRINT | // Human-readable formatting
JSON_UNESCAPED_UNICODE | // Don't escape Unicode characters
JSON_UNESCAPED_SLASHES | // Don't escape forward slashes
JSON_THROW_ON_ERROR // Throw exception instead of returning false
);
// Encoding various types
echo json_encode(42); // 42
echo json_encode('hello'); // "hello"
echo json_encode(true); // true
echo json_encode(null); // null
echo json_encode([1, 2, 3]); // [1,2,3]
Тонкости json_encode
<?php
declare(strict_types=1);
// Sequential array => JSON array
$seq = [0 => 'a', 1 => 'b', 2 => 'c'];
echo json_encode($seq); // ["a","b","c"]
// Non-sequential array => JSON object!
$nonSeq = [0 => 'a', 2 => 'b', 5 => 'c'];
echo json_encode($nonSeq); // {"0":"a","2":"b","5":"c"}
// Force array to be JSON object
$seq = ['a', 'b', 'c'];
echo json_encode($seq, JSON_FORCE_OBJECT); // {"0":"a","1":"b","2":"c"}
// Empty array vs empty object
echo json_encode([]); // []
echo json_encode(new stdClass()); // {}
echo json_encode([], JSON_FORCE_OBJECT); // {}
// NAN and INF
echo json_encode(NAN); // false (encoding fails!)
echo json_encode(INF); // false (encoding fails!)
// json_encode returns false on failure
$result = json_encode("\xB1\x31"); // Invalid UTF-8
var_dump($result); // false
echo json_last_error_msg(); // Malformed UTF-8 characters
Ловушка экзамена: Если массив имеет НЕпоследовательные числовые ключи (например, после
array_filter),json_encode()превратит его в JSON-объект, а не массив! Используйтеarray_values()для переиндексации.
json_decode — декодирование JSON
<?php
declare(strict_types=1);
$json = '{"name":"Alice","age":25,"active":true}';
// Default: returns stdClass object
$obj = json_decode($json);
echo $obj->name; // Alice
echo $obj->age; // 25
// As associative array (second parameter = true)
$arr = json_decode($json, true);
echo $arr['name']; // Alice
echo $arr['age']; // 25
// Depth limit (third parameter)
$deep = '{"a":{"b":{"c":{"d":"value"}}}}';
$result = json_decode($deep, true, 3); // Max depth 3
var_dump($result); // null (too deep!)
// Flags (fourth parameter)
$json = '{"number": 12345678901234567890}';
$data = json_decode($json, true, 512, JSON_BIGINT_AS_STRING);
echo $data['number']; // "12345678901234567890" (as string, not float)
// JSON_THROW_ON_ERROR (PHP 7.3+)
try {
$data = json_decode('invalid json', true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
echo $e->getMessage(); // Syntax error
}
Обработка ошибок
<?php
declare(strict_types=1);
// Old way: check json_last_error()
$data = json_decode('invalid');
if (json_last_error() !== JSON_ERROR_NONE) {
echo json_last_error_msg(); // Syntax error
}
// Error constants
// JSON_ERROR_NONE — No error
// JSON_ERROR_DEPTH — Maximum stack depth exceeded
// JSON_ERROR_STATE_MISMATCH — Invalid or malformed JSON
// JSON_ERROR_CTRL_CHAR — Control character error
// JSON_ERROR_SYNTAX — Syntax error
// JSON_ERROR_UTF8 — Malformed UTF-8 characters
// JSON_ERROR_INF_OR_NAN — Inf and NaN cannot be encoded
// New way (PHP 7.3+): use JSON_THROW_ON_ERROR
try {
$encoded = json_encode($data, JSON_THROW_ON_ERROR);
$decoded = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
echo "JSON Error: " . $e->getMessage();
echo "Error code: " . $e->getCode();
}
Запомни: Всегда используйте
JSON_THROW_ON_ERROR(PHP 7.3+) вместо проверкиjson_last_error(). Это современный и безопасный подход. Без этого флагаjson_decodeпросто вернётnull, и вы можете спутать это с валидным JSON"null".
json_validate (PHP 8.3+)
<?php
declare(strict_types=1);
// PHP 8.3+: Validate JSON without decoding
var_dump(json_validate('{"name":"Alice"}')); // true
var_dump(json_validate('invalid')); // false
var_dump(json_validate('')); // false
var_dump(json_validate('null')); // true
// More efficient than json_decode for validation only
// (doesn't allocate memory for decoded data)
SimpleXML
Чтение XML
<?php
declare(strict_types=1);
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="fiction">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<year>1925</year>
<price>10.99</price>
</book>
<book category="science">
<title lang="en">A Brief History of Time</title>
<author>Stephen Hawking</author>
<year>1988</year>
<price>15.99</price>
</book>
</bookstore>
XML;
// Parse XML string
$books = new SimpleXMLElement($xml);
// Access elements
echo $books->book[0]->title; // The Great Gatsby
echo $books->book[0]->author; // F. Scott Fitzgerald
// Access attributes
echo $books->book[0]['category']; // fiction
echo $books->book[0]->title['lang']; // en
// Iterate over elements
foreach ($books->book as $book) {
echo $book->title . ': $' . $book->price . "\n";
}
// Load from file
$books = simplexml_load_file('books.xml');
// Load from string
$books = simplexml_load_string($xml);
Поиск с XPath
<?php
declare(strict_types=1);
$xml = simplexml_load_string($xmlString);
// XPath queries
$results = $xml->xpath('//book[@category="fiction"]');
foreach ($results as $book) {
echo $book->title . "\n";
}
// Find by attribute value
$results = $xml->xpath('//title[@lang="en"]');
// Find by element value
$results = $xml->xpath('//book[year>1950]');
// Count elements
$count = count($xml->xpath('//book'));
Создание и модификация XML
<?php
declare(strict_types=1);
// Create new XML
$xml = new SimpleXMLElement('<bookstore/>');
// Add child elements
$book = $xml->addChild('book');
$book->addAttribute('category', 'fiction');
$book->addChild('title', 'New Book');
$book->addChild('author', 'Author Name');
$book->addChild('price', '19.99');
// Output XML
echo $xml->asXML();
// Save to file
$xml->asXML('/tmp/books.xml');
// Convert to array (trick)
$array = json_decode(json_encode($xml), true);
Ловушка экзамена: SimpleXML конвертирует элементы в строки автоматически при использовании в строковом контексте. Но при присваивании переменной вы получаете объект
SimpleXMLElement, не строку! Для надёжного получения строки используйте(string)$element.
<?php
declare(strict_types=1);
$xml = new SimpleXMLElement('<root><name>Alice</name></root>');
$name = $xml->name;
var_dump($name); // object(SimpleXMLElement)
var_dump((string)$name); // string(5) "Alice"
// Comparison trap
var_dump($xml->name == 'Alice'); // true (auto-cast to string)
var_dump($xml->name === 'Alice'); // false (object !== string)
DOM (Document Object Model)
Чтение и парсинг
<?php
declare(strict_types=1);
$xmlString = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<users>
<user id="1">
<name>Alice</name>
<email>[email protected]</email>
</user>
<user id="2">
<name>Bob</name>
<email>[email protected]</email>
</user>
</users>
XML;
// Load XML
$dom = new DOMDocument();
$dom->loadXML($xmlString);
// Access elements
$users = $dom->getElementsByTagName('user');
echo $users->length; // 2
foreach ($users as $user) {
$name = $user->getElementsByTagName('name')->item(0)->nodeValue;
$email = $user->getElementsByTagName('email')->item(0)->nodeValue;
$id = $user->getAttribute('id');
echo "[$id] $name: $email\n";
}
// XPath with DOM
$xpath = new DOMXPath($dom);
$results = $xpath->query('//user[@id="1"]/name');
echo $results->item(0)->nodeValue; // Alice
Создание XML с DOM
<?php
declare(strict_types=1);
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
// Create root element
$root = $dom->createElement('catalog');
$dom->appendChild($root);
// Add product element
$product = $dom->createElement('product');
$product->setAttribute('id', '1');
$root->appendChild($product);
// Add child elements
$name = $dom->createElement('name', 'Widget');
$product->appendChild($name);
$price = $dom->createElement('price', '29.99');
$product->appendChild($price);
// Output
echo $dom->saveXML();
// Save to file
$dom->save('/tmp/catalog.xml');
// Load HTML (tolerant of malformed markup)
$dom = new DOMDocument();
@$dom->loadHTML('<h1>Title</h1><p>Text'); // No closing </p> is OK
SimpleXML vs DOM
| Особенность | SimpleXML | DOM |
|---|---|---|
| Простота использования | Высокая | Средняя |
| Объём API | Маленький | Большой |
| Поддержка XPath | Да | Да |
| Создание XML | Ограничено | Полное |
| Работа с HTML | Нет | Да |
| Namespaces | Базовая | Полная |
| Производительность | Быстрее для чтения | Гибче для модификации |
Конвертация между SimpleXML и DOM
<?php
declare(strict_types=1);
// SimpleXML to DOM
$simple = simplexml_load_string('<root><item>test</item></root>');
$domElement = dom_import_simplexml($simple);
$dom = $domElement->ownerDocument;
// DOM to SimpleXML
$dom = new DOMDocument();
$dom->loadXML('<root><item>test</item></root>');
$simple = simplexml_import_dom($dom);
echo $simple->item; // test
Парсинг XML с XMLReader (потоковый)
<?php
declare(strict_types=1);
// XMLReader — memory-efficient for large files
$reader = new XMLReader();
$reader->open('/tmp/large-file.xml');
while ($reader->read()) {
if ($reader->nodeType === XMLReader::ELEMENT && $reader->name === 'product') {
$node = new SimpleXMLElement($reader->readOuterXml());
echo $node->name . ': ' . $node->price . "\n";
}
}
$reader->close();
Запомни: Для больших XML-файлов используйте
XMLReader(потоковый парсинг, низкое потребление памяти) вместоSimpleXMLилиDOM(загружают весь документ в память). Для маленьких файловSimpleXML— самый удобный вариант.