跳到內容

Yaml 組件

編輯此頁

Yaml 組件載入和傾印 YAML 檔案。

這是什麼?

Symfony Yaml 組件剖析 YAML 字串以將其轉換為 PHP 陣列。它也能夠將 PHP 陣列轉換為 YAML 字串。

YAMLYAML 不是標記語言,是一種適用於所有程式語言的人性化資料序列化標準。YAML 是設定檔的絕佳格式。YAML 檔案與 XML 檔案一樣具有表達力,並且與 INI 檔案一樣可讀。

提示

深入了解YAML 規格

安裝

1
$ composer require symfony/yaml

注意

如果您在 Symfony 應用程式外部安裝此組件,則必須在您的程式碼中引入 vendor/autoload.php 檔案,以啟用 Composer 提供的類別自動載入機制。請閱讀這篇文章以取得更多詳細資訊。

為什麼?

快速

Symfony Yaml 的目標之一是在速度和功能之間找到適當的平衡。它僅支援處理設定檔所需的功能。值得注意的缺少功能包括:文件指示詞、多行引號訊息、緊湊區塊集合和多文件檔案。

真正的剖析器

它支援真正的剖析器,並且能夠剖析 YAML 規格的很大一部分子集,以滿足您的所有設定需求。這也表示剖析器非常穩健、易於理解,並且足夠簡單以進行擴展。

清晰的錯誤訊息

每當您的 YAML 檔案出現語法問題時,程式庫都會輸出有用的訊息,其中包含檔案名稱和問題發生的行號。這大大簡化了偵錯。

Dump 支援

它也能夠將 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
// uses 8 spaces for indentation
echo Yaml::dump($array, 2, 8);
1
2
3
4
foo: bar
bar:
        foo: bar
        bar: baz

數字文字

長數字文字,無論是整數、浮點數或十六進位數,都以其在程式碼和設定檔中的可讀性差而聞名。這就是 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() 方法來產生物件的字串表示法。

危險

物件序列化是此實作特有的,其他 PHP YAML 剖析器可能無法識別 php/object 標籤,而非 PHP 實作肯定無法識別 - 請謹慎使用!

將物件剖析和傾印為映射

您可以使用 DUMP_OBJECT_AS_MAP 旗標將物件傾印為 Yaml 映射

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-272016-05-27T02:59:43.1Z (ISO-8601)

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

您可以使用 PARSE_DATETIME 旗標,使其轉換為 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);
// the value of the 'foo' key is a string because it missed the `!php/enum` syntax
// $parameters = ['foo' => 'FooEnum::Foo', 'bar' => FooEnum::Foo];

$yaml = '{ foo: FooEnum::Foo, bar: !php/enum FooEnum::Foo->value }';
$parameters = Yaml::parse($yaml, Yaml::PARSE_CONSTANT);
// the value of the 'foo' key is a string because it missed the `!php/enum` syntax
// $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

在 Symfony 7.1 中引入了對使用不指定案例的列舉 FQCN 的支援。

剖析和傾印二進位資料

非 UTF-8 編碼的字串會傾印為 base64 編碼的資料

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

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

如果二進位資料包含 !!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
# validates a single file
$ php lint.php path/to/file.yaml

# or validates multiple files
$ php lint.php path/to/file1.yaml path/to/file2.yaml

# or all the files in a directory
$ php lint.php path/to/directory

# or all the files in multiple directories
$ php lint.php path/to/directory1 path/to/directory2

# or contents passed to STDIN
$ cat path/to/file.yaml | php lint.php

# you can also exclude one or more files from linting
$ 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

提示

linting 命令也會報告已檢查 YAML 檔案中的任何棄用。例如,這對於在自動化測試期間識別 YAML 檔案內容的棄用可能很有用。

這項作品,包括程式碼範例,已根據 Creative Commons BY-SA 3.0 授權條款授權。
目錄
    版本