言語別 YAML用ライブラリ徹底解説

第4回PHP編

今回は、PHP用のライブラリとして、Syck for PHP、php_yaml、Spycの3つのライブラリを紹介します。

Syck for PHP

Syckは、Cで書かれたYAML用のライブラリです。もともとはRuby 1.8に付属しているライブラリですが、PHP用のバインディングが用意されています。

Syck for PHPについて
Webサイトhttp://whytheluckystiff.net/syck/
ダウンロードhttp://pecl.php.net/package/syck
バ-ジョン0.9.2
ドキュメントなし
その他PHP 5.2.1以上、PEAR Installer 1.4.0以上が必要
作者Alexey Zakhlestin

インストール

インストールはリスト1のように行ってください。

リスト1 Syck for PHPのインストール
$ wget http://pecl.php.net/get/syck-0.9.2.tgz
$ sudo pear install syck-0.9.2.tgz
$ ls /usr/local/lib/php/extensions/no-debug-non-zts-20060613/
syck.so          # syck.so があることを確かめる
$ sudo vi /usr/local/lib/php.ini
### 以下を追加する
###   extension_dir = "/usr/local/lib/php/extensions/no-debug-non-zts-20060613"

使い方

PHPにおけるSyckの使い方は、リスト2のとおりです。基本的に次の関数だけが用意されており、YAMLストリームの読み込みはできません。

syck_load()
YAMLドキュメントを読み込む
syck_dump()
データをYAMLドキュメントに変換する

syck_dump()において、日付と日時(timestamp)はDateTimeクラスのオブジェクトに変換されます。

リスト2 PHPにおけるSyckの使い方(ex-phpsyck1.php)
<?php
// 拡張モジュールsyck.soを読み込む
if (! extension_loaded('syck')) {
    dl('syck.so') or die('cannot load syck extension.');
}

// YAMLドキュメントを読み込む
$str = file_get_contents("example.yaml");
$ydoc = syck_load($str);
var_dump($ydoc);

// データをYAMLドキュメントに変換
echo syck_dump($ydoc);
?>

日本語の扱い

読み込み(syck_load())については、EUCやUTF-8であればsyck_load()で問題ないようです。書き出し(syck_dump())については、日本語はたとえば「\xE3\x81\x84」のようにエンコードされます。エンコードされた文字列でもsyck_load()で問題なく読み込めますが、気になる場合はRubyの場合と同様にSyckのソースコードにパッチを当てることで、エンコードされるのを回避できます。詳しくはRubyでのSyckのセクションをご覧ください。

不具合

yck for PHPは、RubyのSyckと同じ不具合を抱えています。筆者が試したところ、その他に次のような不具合がありました。

syck_load()
循環構造を持つデータがあるとエラーになるリスト3
syck_dump()
  • 独自クラスのインスタンスオブジェクトがYAMLへ変換できない
  • 配列が循環構造を持っているとエラー(Segmentation fault)になるリスト4

syck_dump()を使うなら、現状ではインスタンスオブジェクトは諦めて、代わりに配列を使ったほうがよさそうです。

リスト3 syck_load()は循環構造があるとエラー(SyckException)になる
- &m1
  name: Foo
  child:
    name: Bar
    parent: *m1
リスト4 syck_dump()は循環構造があるとSegmentation faultになる
<?php
$arr1 = array(10);
$arr2 = array(20);
$arr1[] =& $arr2;
$arr2[] =& $arr1;
echo syck_dump($arr1);
?>

その他

PHPでは、無限配列(ArrayやList)と連想配列(HashやMap)の区別がありません。そのため、PHPの配列をsyck_dump()でYAMLドキュメントに変換するとき、YAMLのシーケンスに変換するのか、それともマッピングに変換するのかが問題になります。

実際の動作としては、次のようになるようですリスト5⁠。

  • インデックスが0から始まり、かつ連続していた場合はシーケンスに変換
  • それ以外の場合はマッピングに変換
リスト5 PHPにおける配列の変換(ex-phpsyck2.php)
<?
// インデックスが0から始まり連続していた場合は
// シーケンスへ変換される
$arr = array();
$arr[0] = 10;
$arr[1] = 20;
$arr[2] = 30;
echo syck_dump($arr); //=> [10, 20, 30]

// インデックスが連続していない場合は
// マッピングへ変換される
$arr = array();
$arr[0] = 10;
$arr[2] = 30;
echo syck_dump($arr);  //=> {0: 10, 2: 30}
?>

php_yaml

php_yamlはlibyamlのPHP用ラッパーです。libyamlを使っていますので、Syckと違い、YAML1.1の仕様に沿っています。PHPでYAMLパーサを使いたいなら、現在いちばんお勧めです。

なお余談ですが、作者であるrsky氏は、PHPの言語仕様を強化する拡張モジュールQIQを開発するなど、今注目のプログラマです。

php_yamlについて
ダウンロードhttp://www.opendogs.org/
pub/php_yaml-0.3.0.tgz
バージョン0.3.0
ドキュメントなし
作者Ryusuke Sekiyam(rsky)

インストール

コンパイルするにはlibyamlをあらかじめインストールする必要があります。以下の手順でlibyamlをインストールしてくださいリスト6⁠。

リスト6 libyamlのインストール
$ wget http://pyyaml.org/download/libyaml/yaml-0.0.1.tar.gz
$ tar xzf yaml-0.0.1.tar.gz
$ cd yaml-0.0.1/
$ ./configure
$ make
$ sudo make install

続いて、php_yamlを次の手順でインストールしますリスト7⁠。コンパイルする前に、こちらのパッチ[1]を適用してください。

リスト7 php_yamlのインストール
$ wget http://www.opendogs.org/pub/php_yaml-0.3.0.tgz
$ tar xzf php_yaml-0.3.0.tgz
$ cd php_yaml-0.3.0/
$ wget http://www.kuwata-lab.com/materials/php_yaml-0.3.0.patch
$ patch -p1 

使い方

php_yaml 0.3.0 では以下の関数が用意されています[2]⁠。

yaml_parse($str [, $index [, $count [, $callbacks]]])
YAML文字列を読み込む
yaml_parse_file($str [, $index [, $count [, $callbacks]]])
YAMLファイルを読み込む
yaml_parse_url($str [, $index [, $count [, $callbacks]]])
URLからYAMLドキュメントを読み込む

php_yamlの基本的な使い方は、リスト8のとおりです。

リスト8 PHPにおけるphp_yamlの使い方(ex-phpyaml1.php)
<?php
// 拡張モジュールyaml.soを読み込む
if (! extension_loaded('yaml')) {
    dl('yaml.so') or die('cannot load yaml.so.');
}

// YAMLドキュメントを読み込む
$str = file_get_contents("example.yaml");
$ydoc = yaml_parse($str);
// または $ydoc = yaml_parse_file("example.yaml");
var_dump($ydoc);
?>

ストリームを読み込むときは、何番目のドキュメントを読み込むかをyaml_parse()またはyaml_parse_file()の第2引数で指定できます。また-1を指定すると、すべてのドキュメントを読み込み、配列に格納して返します。第3引数を指定すると、ストリームに含まれるドキュメント数が設定されますリスト9⁠。

リスト9 ストリームを読み込む(ex-phpyaml2.php)
<?php
if (! extension_loaded('yaml')) {
    dl('yaml.so') or die('cannot load yaml.so.');
}

// YAMLストリームを読み込む
$str = file_get_contents("example.yaml");
$ydocs = yaml_parse($str, -1, $count);
// または $ydocs = yaml_parse_file("example.yaml", -1, $count);
var_dump($ydocs);   // YAMLドキュメントの配列
var_dump($count);   // ドキュメント数
?>

なお日付および日時のスカラー値は、デフォルトではパースされずに文字列となります。日付や日時をパースするには、ini_set() を使ってyaml.decode.timestampを1または2に設定しますリスト10⁠。

  • init_set('yaml.decode_timestamp', 1) なら、1970年1月1日 00:00:00からの通算秒を返します
  • init_set('yaml.decode_timestamp', 2)なら、関数date_create()を使ってDateTimeオブジェクトに変換されます

date_create()はPHP 5.1から利用可能なので、関数が存在することを確認してから使ってください。

リスト10  日付や日時のパース(ex-phpyaml3.php)
<?php
if (! extension_loaded('yaml')) {
    dl('yaml.so') or die('cannot load yaml.so.');
}

/// 日付と日時をパースするよう設定する
if (function_exists('date_create')) {
  ini_set('yaml.decode_timestamp', 2);  // DateTimeオブジェクトを使う
} else {
  ini_set('yaml.decode_timestamp', 1);  // 秒数(整数値)を使う
}

$input = <<<END
- 2008-01-01
- 2008-01-01 12:34:56
- 2008-01-01 12:34:56 +9
END;
$ydoc = yaml_parse($input);
var_export($ydoc);
/// 実行結果(yaml.decode_timestampが1のとき):
/// array (
///   0 => 1199113200,
///   1 => 1199158496,
///   2 => 1199158496,
/// )
?>

日本語の扱い

筆者が試した限りでは、EUC-JPやShift_JISではエラーになりましたが、UTF-8であれば問題なく扱うことができました。

タグを変更する

クラスに対応するタグを登録するには、インスタンスオブジェクトを生成するような関数を定義し、それをコールバック関数としてyaml_parse()またはyaml_parse_file()の第4引数に指定しますリスト11⁠。

ただし、タグは「!tagname」ではなく「!<tagname>」と書かないといけないようです。

リスト11 クラスに対応するタグを指定する(ex-phpyaml4.php)
<?php
if (! extension_loaded('yaml')) {
    dl('yaml.so') or die('cannot load yaml.so.');
}

/// クラス定義
class Color {
  var $r, $g, $b;
  function __construct($r, $g, $b) {
    $this->r = $r;
    $this->g = $g;
    $this->b = $b;
  }
  /// オブジェクトを生成するstaticメソッド
  static function create($arr) {
    return new Color($arr['r'], $arr['g'], $arr['b']);
  }
}

/// YAMLドキュメント
$input = <<<END
- !<color>
  r: 0
  g: 127
  b: 255
END;

/// タグ名と、オブジェクトを生成するコールバック関数名を
/// 指定してパースする
$callbacks = array(
  'color'=>'Color::create',
);
$ydoc = yaml_parse($input, 0, $count, $callbacks);
var_export($ydoc);

/// 実行結果:
/// array (
///   0 =>
///   Color::__set_state(array(
///      'r' => 0,
///      'g' => 127,
///      'b' => 255,
///   )),
/// )
?>

不具合

筆者が試した範囲では、以下のような不具合がありました。

  • マッピングのマージ(<<)に未対応
  • マッピングのデフォルト値(=)に未対応
  • 値がないときにNULLにならず空文字列になる(パッチで修正済み)
  • 「2008-01-01 12:34:56」のパターンの日時がパースできず文字列となる(パッチで修正済み)
  • 'y'や'n'が文字列ではなく真偽値と見なされる[3]

その他

php_yamlはlibyamlを使っているだけあって、YAML 1.1の仕様に忠実です。PHPでYAMLパーサが必要なら、現時点でいちばんお勧めです。将来的にはyaml_emitter()が実装されることに期待しましょう。

Spyc

Spycは、PHPで実装されたYAML用ライブラリです。Pure PHPですので、拡張ライブラリがインストールできない場合には重宝します。ただし拡張ライブラリが使えるのであれば、速さの点でも機能の点でも、Syckやphp_yamlをつかうほうがよいでしょう。

Spycについて
Webサイトhttp://spyc.sourceforge.net/
ダウンロードhttp://sourceforge.net/project/
showfiles.php?group_id=141902
バージョン0.3(beta)
作者Chris Wanstrath, Vlad Andersen

インストール

インストールは、上記ページからspyc-0.3.beta.tar.gzをダウンロードして解凍し、spyc.php(PHP 4用)またはspyc.PHP 5(PHP 5用)を適切なディレクトリにコピーするだけですリスト12⁠。

リスト12 Spycのインストール
$ wget http://downloads.sourceforge.net/spyc/spyc-0.3.beta.tar.gz
$ cd spyc/
$ sudo cp spyc.php5 /usr/local/lib/php/spyc.php

使い方

Spycの基本的な使い方はリスト13のとおりです。機能としては次の2つだけであり、YAMLストリームの読み込みはできません。

Spyc::YAMLLoad($filename)
YAMLドキュメントを読み込む
Spyc::YAMLDump($data)
データをYAMLドキュメントに変換する

またSpyc::YAMLLoad()の引数にはファイル名を指定するため、YAML文字列を読み込むことはできないようです。

リスト13 Spycの使い方(ex-spyc1.php)
<?php
/// Syckを読み込む
require_once("spyc.php");

/// YAMLドキュメントファイルを読み込む
$data = Spyc::YAMLLoad("example.yaml");
var_dump($data);
/// または
///   $spyc = new Spyc();
///   $data = $spyc->load("example.yaml");

/// データをYAMLドキュメントに変換
echo Spyc::YAMLDump($data);
/// または
///   $spyc = new Spyc();
///   echo $spyc->dump($data);
?>

タグを変更する

Spycはタグをサポートしていません。

日本語の扱い

日本語は、EUCまたはUTF-8であれば特に問題はないようです。Spyc::YAMLDump()において日本語がエンコードされることもありません。

不具合

筆者が試した限りでは、以下のような不具合がありました。

Spyc::YAMLLoad()
  • スカラーへのアンカーとエイリアスが解釈できない
  • 「&m1 {A: 10}」のようにアンカーとデータを同一行に書くと解釈されない
  • 日付や日時(timestamp)が未サポート
  • 「null」「~」が未サポート
  • マッピングのマージが未サポート
  • ブロックスタイルの文字列があると無限ループになる
  • 値がない場合にnullではなく空文字列になる
  • マッピングのキーに日本語を使用すると文字化けする
  • ルート要素がフロースタイルだと解釈できない
  • フロースタイルに改行が入っていると解釈できない
Spyc::YAMLDump()
  • ルート要素がスカラーだとエラーになる
  • 配列のキーが数字であれば必ずシーケンスに変換される
  • マッピングとシーケンスが混ざって出力されることがあるリスト14
リスト14 シーケンスとマッピングが混ざった例
<?php
require_once("spyc.php");
$data = array('a', 'b'=>10, '4'=>'c');
echo Spyc::YAMLDump($data);
/// 実行結果:
///   ---
///   - a
///   b: 10
///   - c
?>

その他

Spycは、symphonyフレームワークなどで使われています。

おすすめ記事

記事・ニュース一覧