Привет, Хабр! Сегодня я расскажу вам о том, как использовать YAML‑парсер в Symfony.

YAML — это человекочитаемый формат сериализации данных, который используется для конфигурационных файлов. И в Symfony для этого есть компонент Yaml, который позволяет парсить YAML‑строки и файлы в PHP‑значения и обратно.

Компонент Yaml состоит из двух основных классов:

  1. Parser: парсит YAML‑строки и файлы в PHP‑значения.

  2. Dumper: преобразует PHP‑значения обратно в YAML‑строки.

Для упрощения есть фасадный класс Yaml, который имеет статические методы для наиболее распространенных операций.

Чтение YAML-строк и файлов

Чтобы распарсить YAML‑строку, есть метод Yaml::parse():

use Symfony\Component\Yaml\Yaml;

$yamlString = "
foo: bar
baz:
  - qux
  - quux
";

$data = Yaml::parse($yamlString);

// $data будет содержать:
// [
//     'foo' => 'bar',
//     'baz' => ['qux', 'quux'],
// ]

Для чтения YAML из файла метод Yaml::parseFile():

use Symfony\Component\Yaml\Yaml;

$data = Yaml::parseFile('/path/to/file.yaml');

Если в процессе парсинга произойдет ошибка, будет выброшено исключение ParseException. Лучше обрабатывать это исключение, чтобы получать информацию об ошибке:

use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;

try {
    $data = Yaml::parseFile('/path/to/file.yaml');
} catch (ParseException $exception) {
    printf('Не удалось распарсить YAML: %s', $exception->getMessage());
}

Чтобы преобразовать PHP‑значение в YAML‑строку, используйте метод Yaml::dump():

use Symfony\Component\Yaml\Yaml;

$data = [
    'foo' => 'bar',
    'baz' => ['qux', 'quux'],
];

$yamlString = Yaml::dump($data);

// $yamlString будет содержать:
// foo: bar
// baz:
//     - qux
//     - quux

Можно настроить уровень вложенности, при котором массивы будут инлайнены, передав второй аргумент в метод dump():

$yamlString = Yaml::dump($data, 1);

// $yamlString будет содержать:
// foo: bar
// baz: [qux, quux]

Yaml поддерживает сериализацию и десериализацию объектов. Для этого при дампе данных необходимо использовать флаг Yaml::DUMP_OBJECT:

use Symfony\Component\Yaml\Yaml;

$object = new \stdClass();
$object->foo = 'bar';

$yamlString = Yaml::dump($object, 2, 4, Yaml::DUMP_OBJECT);

// $yamlString будет содержать:
// !php/object 'O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}'

При парсинге такого YAML необходимо использовать флаг Yaml::PARSE_OBJECT:

use Symfony\Component\Yaml\Yaml;

$yamlString = "!php/object 'O:8:\"stdClass\":1:{s:3:\"foo\";s:3:\"bar\";}'";

$data = Yaml::parse($yamlString, Yaml::PARSE_OBJECT);

// $data будет объектом stdClass с свойством foo, равным 'bar'

Также YAML поддерживает различные типы данных, такие как даты, булевы значения и т. д. Компонент Yaml автоматом преобразует их в соответствующие PHP‑значения:

is_active: true
created_at: 2025-02-08
use Symfony\Component\Yaml\Yaml;

$yamlString = "
is_active: true
created_at: 2025-02-08
";

$data = Yaml::parse($yamlString);

// $data будет содержать:
// [
//     'is_active' => true,
//     'created_at' => new \DateTime('2025-02-08'),
// ]

Помимо этого, можно использовать пользовательские теги для обозначения специальных типов данных. Компонент Yaml позволяет работать с такими тегами с помощью класса TaggedValue:

custom_tag: !mytag
  foo: bar
use Symfony\Component\Yaml\Tag\TaggedValue;
use Symfony\Component\Yaml\Yaml;

$yamlString = "
custom_tag: !mytag
  foo: bar
";

$data = Yaml::parse($yamlString, Yaml::PARSE_CUSTOM_TAGS);

// $data будет содержать:
// [
//     'custom_tag' => new TaggedValue('mytag', ['foo' => 'bar']),
// ]

Пример использования YAML-парсера

Представим, что у нас есть YAML‑файл, описывающий конфигурацию приложения с различными средами (development, testing, production), настройками базы данных, кэша и сервисов:

environments:
  development:
    debug: true
    database:
      host: localhost
      port: 3306
      name: dev_db
      user: dev_user
      password: dev_pass
    cache:
      enabled: false
  testing:
    debug: true
    database:
      host: localhost
      port: 3306
      name: test_db
      user: test_user
      password: test_pass
    cache:
      enabled: true
      type: memory
  production:
    debug: false
    database:
      host: db.prod.example.com
      port: 3306
      name: prod_db
      user: prod_user
      password: prod_pass
    cache:
      enabled: true
      type: redis
      host: cache.prod.example.com
      port: 6379
services:
  email:
    provider: smtp
    host: smtp.example.com
    port: 587
    username: no-reply@example.com
    password: email_pass
  payment:
    provider: stripe
    api_key: sk_live_12345

Задача: написать скрипт на PHP, который будет читать этот файл и выводить настройки для указанной среды.

require 'vendor/autoload.php';

use Symfony\Component\Yaml\Yaml;
use Symfony\Component\Yaml\Exception\ParseException;

function getConfigForEnvironment($env) {
    try {
        $config = Yaml::parseFile('app_config.yaml');
    } catch (ParseException $e) {
        printf('Не удалось разобрать YAML: %s', $e->getMessage());
        return null;
    }

    if (!isset($config['environments'][$env])) {
        echo "Среда '$env' не найдена в конфигурации." . PHP_EOL;
        return null;
    }

    $envConfig = $config['environments'][$env];
    $servicesConfig = $config['services'];

    return [
        'environment' => $envConfig,
        'services' => $servicesConfig
    ];
}

// Пример использования
$environment = 'production';
$config = getConfigForEnvironment($environment);

if ($config) {
    echo "Настройки для среды '$environment':" . PHP_EOL;
    print_r($config['environment']);

    echo "Настройки сервисов:" . PHP_EOL;
    print_r($config['services']);
}

Вывод:

Настройки для среды 'production':
Array
(
    [debug] => 
    [database] => Array
        (
            [host] => db.prod.example.com
            [port] => 3306
            [name] => prod_db
            [user] => prod_user
            [password] => prod_pass
        )

    [cache] => Array
        (
            [enabled] => 1
            [type] => redis
            [host] => cache.prod.example.com
            [port] => 6379
        )

)
Настройки сервисов:
Array
(
    [email] => Array
        (
            [provider] => smtp
            [host] => smtp.example.com
            [port] => 587
            [username] => no-reply@example.com
            [password] => email_pass
        )

    [payment] => Array
        (
            [provider] => stripe
            [api_key] => sk_live_12345
        )

)

Ограничения

Компонент Yaml не поддерживает некоторые возможности YAML 1.2, такие как:

  • Многостраничные документы (--- и ... маркеры);

  • Комплексные ключи в маппингах;

  • Некоторые теги и типы (!!set, !!omap, !!pairs и т. д.).


В заключение хочу напомнить про открытый урок, который пройдёт в Otus 13 февраля — «Генерируем API-клиент без помощи ChatGPT». На нём вы научитесь генерировать API-клиент на базе спецификации Open API и использовать его в своих приложениях. Записаться можно на странице курса "Symfony Framework".

Комментарии (1)


  1. DarkHost
    11.02.2025 04:37

    Спасибо за статью