Компонент Yaml

Дата обновления перевода 2024-07-10

Компонент Yaml

Компонент Yaml загружает и сбрасывает файлы YAML.

Что это?

Компонент Symfony Yaml анализирует YAML строки, чтобы преобразовать их в PHP массивы. Он также может преобразовывать PHP массивы в YAML строки.

YAML, YAML не является языком разметки - это дружелюбный стандарт сериализации данных для всех языков программирования. YAML является отличным форматом для ваших файлов конфигурации. Файлы YAML так же экспрессивны, как файлы XML, и так же читаемы, как файлы INI.

Tip

Узнайте больше о спецификациях YAML.

Установка

1
$ composer require symfony/yaml

Note

Если вы устанавливаете этот компонент вне приложения Symfony, вам нужно подключить файл vendor/autoload.php в вашем коде для включения механизма автозагрузки классов, предоставляемых Composer. Детальнее читайте в этой статье.

Почему?

Скорость

Одна из целей Symfony Yaml - найти правильный баланс между скоростью и функциональностью. Он поддерживает только необходимые функции для обработки файлов конфигурации. Не хватает таких заметных функций: директив документов, многострочных цитируемых сообщений, компактных коллекций блоков и многодокументных файлов.

Реальный парсер

Поддерживает реальный парсер и понимает большую часть спецификации YAML для всех ваших потребностей конфигурации. Это также означает, что парсер достаточно обширен, легок в понимании и достаточно прост для расширения.

Ясные сообщения ошибок

Каждый раз, когда у вас есть проблема синтаксиса в ваших YAML файлах, библиотека выводит полезное сообщение с именем файла и номером строки, где возникла проблема. Это очень облегчает отладку.

Поддержка сброса

Он также может сбрасывать PHP массивы в YAML с поддержкой объектов, и встраиваемый уровень конфигурации для красивых выводов.

Поддержка типов

Поддерживает большинство встроенных типов YAML вроде дат, целых чисел, чисел в восьмеричной системе, булевых значений и многие другие...

Поддержка ключей полного слияния

Полная поддержка ссылок, дополнительных имён и ключей полного слияния. Не повторяйте самостоятельно, ссылаясь на распространённые части конфигурации.

Использование компонента Symfony YAML

Компонент Symfony Yaml состоит из двух главных классов: один анализирует YAML строки (Parser), а второй - сбрасывает PHP массив в строку YAML (Dumper).

Поверх этих двух классов, класс Yaml работает как тонкая прослойка и упрощает частые варианты использования.

Чтение содержания YAML

Метод parse() анализирует строку YAML и преобразует её в PHP массив:

1
2
3
4
use Symfony\Component\Yaml\Yaml;

$value = Yaml::parse("foo: bar");
// $value = ['foo' => 'bar']

Если ошибка возникает во время анализа, парсер вызывает исключение ParseException, показывая тип ошибки и строчку исходной строки YAML, где возникла ошибка:

1
2
3
4
5
6
7
use Symfony\Component\Yaml\Exception\ParseException;

try {
    $value = Yaml::parse('...');
} catch (ParseException $exception) {
    printf('Unable to parse the YAML string: %s', $exception->getMessage());
}

Чтение файлов YAML

Метод parseFile() анализирует содержание YAML в указанном файле и преобразует его в PHP значение:

1
2
3
use Symfony\Component\Yaml\Yaml;

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

Если во время анализа возникает ошибка, парсер вызывает исключение ParseException.

Запись YAML-файлов

Метод dump() преобразует любой PHP массив в его представление YAML:

1
2
3
4
5
6
7
8
9
10
use Symfony\Component\Yaml\Yaml;

$array = [
    'foo' => 'bar',
    'bar' => ['foo' => 'bar', 'bar' => 'baz'],
];

$yaml = Yaml::dump($array);

file_put_contents('/path/to/file.yaml', $yaml);

Если ошибка возникает во время сброса, парсер вызывает исключение DumpException.

Расширенные и вставленные массивы

Формат YAML поддерживает два типа представления для массивов, расширенное и вставленное. По умолчанию, дампер использует расширенное представление:

1
2
3
4
foo: bar
bar:
    foo: bar
    bar: baz

Второй аргумент метода dump() настраивает уровень, на котором вывод переключается с расширенного представления на вставленное:

1
echo Yaml::dump($array, 1);
1
2
foo: bar
bar: { foo: bar, bar: baz }
1
echo Yaml::dump($array, 2);
1
2
3
4
foo: bar
bar:
    foo: bar
    bar: baz

Отступы

По умолчанию, компонент YAML использует 4 пробела для отступа. Это может поменять с помощью третьего аргумента таким образом:

1
2
// использует 8 пробелов для отступа
echo Yaml::dump($array, 2, 8);
1
2
3
4
foo: bar
bar:
        foo: bar
        bar: baz

Числовые литералы

Длинные числовые литералы, будь они целыми числами, float или шестнадцатиричными, известны своей плохой читаемостью в коде и файлах конфигурации. Поэтому файлы YAML позволяют добавлять нижние подчёркивания для улучшения их читаемости:

1
2
3
4
5
parameters:
    credit_card_number: 1234_5678_9012_3456
    long_number: 10_000_000_000
    pi: 3.14159_26535_89793
    hex_words: 0x_CAFE_F00D

Во время анализа содержания YAML, все символы _ удаляются из содержания числовых литералов, поэтому лимита количества нижних подчёркиваний, которые вы можете включать или то, как вы группируете содержание, не существует.

Продвинутое использование: флажки

Анализ объектов и сброс

Вы можете сбрасывать объекты, используя флаг DUMP_OBJECT:

1
2
3
4
5
$object = new \stdClass();
$object->foo = 'bar';

$dumped = Yaml::dump($object, 2, 4, Yaml::DUMP_OBJECT);
// !php/object 'O:8:"stdClass":1:{s:5:"foo";s:7:"bar";}'

И анализировать их, используя флаг PARSE_OBJECT:

1
2
3
$parsed = Yaml::parse($dumped, Yaml::PARSE_OBJECT);
var_dump(is_object($parsed)); // true
echo $parsed->foo; // bar

Компонент YAML использует метод PHP serialize() для генерирования представления строки объекта.

Danger

Сериализация объекта специфична для этой реализации, другие парсеры PHP YAML скорее всего не узнают тег php/object, а не-PHP реализации точно не узнают - используйте с осторожностью!

Анализ и сброс объектов в виде карт

Вы можете сбрасывать объекты, как Yaml-карты, используя флаг DUMP_OBJECT_AS_MAP:

1
2
3
4
5
$object = new \stdClass();
$object->foo = 'bar';

$dumped = Yaml::dump(['data' => $object], 2, 4, Yaml::DUMP_OBJECT_AS_MAP);
// $dumped = "data:\n    foo: bar"

И анализировать их, используя флаг PARSE_OBJECT_FOR_MAP:

1
2
3
4
$parsed = Yaml::parse($dumped, Yaml::PARSE_OBJECT_FOR_MAP);
var_dump(is_object($parsed)); // true
var_dump(is_object($parsed->data)); // true
echo $parsed->data->foo; // bar

Компонент YAML использует приведение PHP (array), чтобы сгенерировать строчное представление объекта в виде карты.

Работа с невалидными типами

По умолчанию, парсер закодирует невалидные типы, как null. Вы можете заставить парсер вызывать исключения, используя флаг PARSE_EXCEPTION_ON_INVALID_TYPE:

1
2
$yaml = '!php/object \'O:8:"stdClass":1:{s:5:"foo";s:7:"bar";}\'';
Yaml::parse($yaml, Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE); // throws an exception

Схожим образом вы можете использовать DUMP_EXCEPTION_ON_INVALID_TYPE при дампе:

1
2
$data = new \stdClass(); // by default objects are invalid.
Yaml::dump($data, 2, 4, Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE); // throws an exception

Работа с датами

По умолчанию, парсер YAML преобразует строки без кавычек, которые будут выглядеть как дата или дата-время во временную метку Unix; например, 2016-05-27 или 2016-05-27T02:59:43.1Z (ISO-8601):

1
Yaml::parse('2016-05-27'); // 1464307200

Вы можете заставить его преобразовывать в экземпляр DateTime, используя флаг PARSE_DATETIME:

1
2
$date = Yaml::parse('2016-05-27', Yaml::PARSE_DATETIME);
var_dump(get_class($date)); // DateTime

Сброс многострочных блоков литералов

В YAML многострочные строки могут быть представлены, как блоки литералов. По умолчанию, дампер закодирует много строк в виде инлайновой строки:

1
2
3
$string = ["string" => "Multiple\nLine\nString"];
$yaml = Yaml::dump($string);
echo $yaml; // string: "Multiple\nLine\nString"

Вы можете заставить его использовать блок литералов с помощью флага DUMP_MULTI_LINE_LITERAL_BLOCK:

1
2
3
4
5
6
7
$string = ["string" => "Multiple\nLine\nString"];
$yaml = Yaml::dump($string, 2, 4, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK);
echo $yaml;
//  string: |
//       Multiple
//       Line
//       String

Анализ PHP-констант

По умолчанию, YAML-парсер относится к PHP константам, включенным в содержание, как в обычным строкам. Используйте флаг PARSE_CONSTANT и специальный синтаксис !php/const, чтобы проанализировать их, как соответствующие PHP константы:

1
2
3
$yaml = '{ foo: PHP_INT_SIZE, bar: !php/const PHP_INT_SIZE }';
$parameters = Yaml::parse($yaml, Yaml::PARSE_CONSTANT);
// $parameters = ['foo' => 'PHP_INT_SIZE', 'bar' => 8];

Анализ PHP-исчислений

Парсер YAML поддерживает PHP-исчисления, как модульные, так и бэк-энда. По умолчанию, они анализируются как обычные строки. Используйте флаг PARSE_CONSTANT и специальный синтаксис !php/enum, чтобы анализировать их как реальные PHP-исчисления:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
enum FooEnum: string
{
    case Foo = 'foo';
    case Bar = 'bar';
}

// ...

$yaml = '{ foo: FooEnum::Foo, bar: !php/enum FooEnum::Foo }';
$parameters = Yaml::parse($yaml, Yaml::PARSE_CONSTANT);
// значение ключа 'foo' - это строка, так как она пропустила синтаксис `!php/enum`
// $parameters = ['foo' => 'FooEnum::Foo', 'bar' => FooEnum::Foo];

$yaml = '{ foo: FooEnum::Foo, bar: !php/enum FooEnum::Foo->value }';
$parameters = Yaml::parse($yaml, Yaml::PARSE_CONSTANT);
// значение ключа 'foo' - это строка, так как она пропустила синтаксис `!php/enum`
// $parameters = ['foo' => 'FooEnum::Foo', 'bar' => 'foo'];

Вы также можете использовать !php/enum, чтобы получить все случаи исчислений,
указав только исчисление FQCN:

1
2
3
4
5
6
7
8
9
10
11
enum FooEnum: string
{
    case Foo = 'foo';
    case Bar = 'bar';
}

// ...

$yaml = '{ bar: !php/enum FooEnum }';
$parameters = Yaml::parse($yaml, Yaml::PARSE_CONSTANT);
// $parameters = ['bar' => ['foo', 'bar']];

7.1

Поддержка использования исчисления FQCN без указания регистра
была введена в Symfony 7.1.

Анализ и сброс бинарных данных

Вы можете сбросить бинарные данные, используя флаг DUMP_BASE64_BINARY_DATA:

1
2
3
4
$imageContents = file_get_contents(__DIR__.'/images/logo.png');

$dumped = Yaml::dump(['logo' => $imageContents], 2, 4, Yaml::DUMP_BASE64_BINARY_DATA);
// logo: !!binary iVBORw0KGgoAAAANSUhEUgAAA6oAAADqCAY...

Бинарные данные автоматичеки анализируются, если они включают в себя флаг YAML !!binary (нет необходимости передавать какой-либо флаг парсеру Yaml):

1
2
3
$dumped = 'logo: !!binary iVBORw0KGgoAAAANSUhEUgAAA6oAAADqCAY...';
$parsed = Yaml::parse($dumped);
$imageContents = $parsed['logo'];

Анализ и сброс пользовательских тегов

Кроме встроенной поддержки тегов вроде !php/const и !!binary, вы можете определить ваши собственные YAML теги и анализировать их с помощью флага PARSE_CUSTOM_TAGS:

1
2
3
4
5
$data = "!my_tag { foo: bar }";
$parsed = Yaml::parse($data, Yaml::PARSE_CUSTOM_TAGS);
// $parsed = Symfony\Component\Yaml\Tag\TaggedValue('my_tag', ['foo' => 'bar']);
$tagName = $parsed->getTag();    // $tagName = 'my_tag'
$tagValue = $parsed->getValue(); // $tagValue = ['foo' => 'bar']

Если содержание для сброса содержит объекты TaggedValue, то они автоматически преобразуются в YAML теги:

1
2
3
4
5
use Symfony\Component\Yaml\Tag\TaggedValue;

$data = new TaggedValue('my_tag', ['foo' => 'bar']);
$dumped = Yaml::dump($data);
// $dumped = '!my_tag { foo: bar }'

Сброс Null-значений

Официальная спецификация YAML использует и null, и ~ для представления значения null. Этот компонент использует по умолчанию null при сбросе значений null, но вы можете сбрасывать их как ~ с флагом DUMP_NULL_AS_TILDE:

1
2
3
4
5
$dumped = Yaml::dump(['foo' => null]);
// foo: null

$dumped = Yaml::dump(['foo' => null], 2, 4, Yaml::DUMP_NULL_AS_TILDE);
// foo: ~

Сброс числовых ключей как строк

По умолчанию По умолчанию ключи массива, состоящего только из цифр, передаются в виде целых чисел. Для того чтобы сбрасывать только строковые ключи, вы можете использовать флажок DUMP_NUMERIC_KEY_AS_STRING:

1
2
3
4
5
$dumped = Yaml::dump([200 => 'foo']);
// 200: foo

$dumped = Yaml::dump([200 => 'foo'], 2, 4, Yaml::DUMP_NUMERIC_KEY_AS_STRING);
// '200': foo

Валидация синтаксиса

Синтаксис содержания YAML может быть валидирован через CLI, используя команду LintCommand.

Для начала, установите компонент Console:

1
$ composer require symfony/console

Создайте консольное приложение с lint:yaml в качестве его единственной команды:

1
2
3
4
5
6
7
8
9
// lint.php
use Symfony\Component\Console\Application;
use Symfony\Component\Yaml\Command\LintCommand;

(new Application('yaml/lint'))
    ->add(new LintCommand())
    ->getApplication()
    ->setDefaultCommand('lint:yaml', true)
    ->run();

Далее, выполните скрипт для валидации содержания:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# валидирует один файл
$ php lint.php path/to/file.yaml

# или валидирует несколько файлов
$ php lint.php path/to/file1.yaml path/to/file2.yaml

# или все файлы в каталоге
$ php lint.php path/to/directory

# или все файлы в нескольких каталогах
$ php lint.php path/to/directory1 path/to/directory2

# или содержание, переданное STDIN
$ cat path/to/file.yaml | php lint.php

# вы также можете исключить один или более файлов из проверки
$ php lint.php path/to/directory --exclude=path/to/directory/foo.yaml --exclude=path/to/directory/bar.yaml

Результат записывается в STDOUT и использует формат простого текста по умолчанию. Добавьте опцию --format, чтобы получить вывод в формате JSON:

1
$ php lint.php path/to/file.yaml --format json

Tip

Команда проверки соблюдения стандартов кода также сообщит обо всех устареваниях в провеяемых YAML файлах. Это может быть, к примеру, быть полезным для определения устареваний содержания YAML файлов во время автоматизированных тестов.