[PHP]yaml_emit_fileとは?PHPの値をYAMLファイルとして直接書き出す方法を徹底解説

PHP

はじめに

前回の記事では、PHPの値をYAML形式の文字列に変換する yaml_emit() を解説しました。その中の実践例では、yaml_emit() で生成した文字列を file_put_contents() でファイルに保存するパターンを紹介しましたが、実はyaml拡張には、この一連の処理を1回の関数呼び出しでまとめて行える yaml_emit_file() という専用関数が用意されています。

yaml_emit_file() は、文字列変換とファイル書き込みという2つのステップを内部で完結させてくれる、利便性を重視した関数です。設定ファイルの自動生成や、キャッシュデータの永続化など、「変換した結果を必ずファイルに保存する」という用途が明確な場合に、コードをシンプルにできます。本記事では基本的な使い方から、実践的な活用パターンまで詳しく解説します。


関数概要

項目内容
関数名yaml_emit_file()
所属拡張yaml拡張(PECL、標準では無効)
シグネチャyaml_emit_file(string $filename, mixed $data, int $encoding = YAML_ANY_ENCODING, int $linebreak = YAML_ANY_BREAK, array $callbacks = []): bool
引数1$filename — 書き込み先のファイルパス
引数2$data — YAML形式に変換したいPHPの値
引数3$encoding — 出力の文字エンコーディング
引数4$linebreak — 改行コードの形式
引数5$callbacks — カスタムのシリアライズ処理を指定するコールバック配列
戻り値成功時に true、失敗時に false
対応バージョンyaml拡張2.0.0以降(PECL)
対になる関数yaml_parse_file()(YAMLファイルを読み込んでPHPの値に変換)

処理の流れ(イメージ図)

  PHPの配列データ
  ['app' => ['name' => 'MyApp', 'debug' => false]]
              │
              ▼
   yaml_emit_file('/path/to/config.yaml', $data)
              │
   ┌──────────┴──────────────┐
   │ 内部的に以下の2ステップを実行  │
   │ 1. データをYAML文字列に変換    │
   │ 2. 指定パスにファイルとして書き込み │
   └──────────┬──────────────┘
              ▼
  /path/to/config.yaml というファイルが
  YAML形式の内容で作成される

ポイントは、yaml_emit() + file_put_contents() という2行の処理を、yaml_emit_file() という1回の呼び出しに集約できるという点です。単純な「変換してファイルに保存する」というユースケースにおいては、コードの見通しが良くなります。


実践サンプル7選

例1:基本的な使い方

<?php

class BasicYamlFileWriter
{
    public function write(string $filePath, array $data): bool
    {
        if (!extension_loaded('yaml')) {
            throw new RuntimeException('yaml拡張がインストールされていません。');
        }

        // 変換と書き込みを1回の呼び出しで行う
        return yaml_emit_file($filePath, $data);
    }
}

$writer = new BasicYamlFileWriter();
var_dump($writer->write('/tmp/basic_config.yaml', ['name' => '太郎', 'age' => 30]));

例2:戻り値をチェックして書き込み失敗を検知するクラス

<?php

class SafeYamlFileWriter
{
    /**
     * yaml_emit_file()の戻り値(成功/失敗)を確認し、
     * 失敗時には例外をスローする
     */
    public function writeStrict(string $filePath, array $data): void
    {
        $success = yaml_emit_file($filePath, $data);

        if (!$success) {
            throw new RuntimeException("YAMLファイルの書き込みに失敗しました: {$filePath}");
        }
    }
}

$writer = new SafeYamlFileWriter();
try {
    $writer->writeStrict('/tmp/strict_config.yaml', ['db' => ['host' => 'localhost']]);
    echo '書き込みに成功しました' . PHP_EOL;
} catch (RuntimeException $e) {
    echo 'エラー: ' . $e->getMessage() . PHP_EOL;
}

例3:ディレクトリの存在確認と作成を含めた堅牢な書き込みクラス

<?php

class DirectoryAwareYamlWriter
{
    /**
     * 書き込み先のディレクトリが存在しない場合、
     * 事前に作成してからyaml_emit_file()を呼び出す
     */
    public function write(string $filePath, array $data): bool
    {
        $directory = dirname($filePath);

        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }

        return yaml_emit_file($filePath, $data);
    }
}

$writer = new DirectoryAwareYamlWriter();
var_dump($writer->write('/tmp/nested/dir/config.yaml', ['setting' => 'value']));

例4:アプリケーション設定を環境別に出力するツール

<?php

class EnvironmentConfigExporter
{
    /**
     * 開発・ステージング・本番など、
     * 環境ごとに異なるYAML設定ファイルを一括生成する
     */
    public function exportAll(array $environments, string $outputDir): array
    {
        $results = [];

        foreach ($environments as $envName => $config) {
            $filePath = "{$outputDir}/{$envName}.yaml";
            $results[$envName] = yaml_emit_file($filePath, $config);
        }

        return $results;
    }
}

$exporter = new EnvironmentConfigExporter();
print_r($exporter->exportAll([
    'development' => ['debug' => true, 'db_host' => 'localhost'],
    'production'  => ['debug' => false, 'db_host' => 'prod-db.example.com'],
], '/tmp/configs'));

例5:一時ファイルに書き出してからアトミックに置き換えるクラス

<?php

class AtomicYamlFileWriter
{
    /**
     * 一時ファイルに書き込んでから最終的な名前にリネームすることで、
     * 書き込み途中の不完全なファイルが読み込まれるリスクを減らす
     */
    public function writeAtomically(string $filePath, array $data): bool
    {
        $tempPath = $filePath . '.tmp';

        if (!yaml_emit_file($tempPath, $data)) {
            return false;
        }

        return rename($tempPath, $filePath);
    }
}

$writer = new AtomicYamlFileWriter();
var_dump($writer->writeAtomically('/tmp/atomic_config.yaml', ['version' => '1.0']));

例6:既存のYAMLファイルをバックアップしてから上書きするクラス

<?php

class BackupBeforeOverwriteWriter
{
    /**
     * 既存のYAMLファイルがある場合はバックアップを作成してから
     * 新しい内容で上書きする
     */
    public function writeWithBackup(string $filePath, array $data): bool
    {
        if (file_exists($filePath)) {
            $backupPath = $filePath . '.bak.' . date('YmdHis');
            copy($filePath, $backupPath);
        }

        return yaml_emit_file($filePath, $data);
    }
}

$writer = new BackupBeforeOverwriteWriter();
var_dump($writer->writeWithBackup('/tmp/backed_up_config.yaml', ['updated' => true]));

例7:yaml_emit()との使い分けを示す比較デモ

<?php

class EmitVsEmitFileComparison
{
    /**
     * 文字列として結果を加工したい場合はyaml_emit()、
     * 直接ファイルに保存したいだけならyaml_emit_file()という使い分けを示す
     */
    public function demonstrateStringManipulation(array $data): string
    {
        // 文字列として取得し、コメントを先頭に追加してから保存するケース
        $yamlString = yaml_emit($data);
        $withComment = "# このファイルは自動生成されています\n" . $yamlString;
        file_put_contents('/tmp/commented_config.yaml', $withComment);

        return $withComment;
    }

    public function demonstrateDirectFileWrite(array $data): bool
    {
        // 単純にファイルへ保存するだけならこちらの方が簡潔
        return yaml_emit_file('/tmp/direct_config.yaml', $data);
    }
}

$comparison = new EmitVsEmitFileComparison();
echo $comparison->demonstrateStringManipulation(['key' => 'value']);
var_dump($comparison->demonstrateDirectFileWrite(['key' => 'value']));

関連関数との比較

関数役割yaml_emit_fileとの違い
yaml_emit_file()PHPの値をYAML形式に変換し、直接ファイルに書き込む本記事の対象。変換と保存をまとめて行う
yaml_emit()PHPの値をYAML形式の文字列に変換文字列として結果を受け取り、加工の余地がある
yaml_parse_file()YAMLファイルを読み込んでPHPの値に変換yaml_emit_file()の対になるデコード関数
file_put_contents()文字列を任意のファイルに書き込むyaml_emit()と組み合わせることで同様の処理を実現できる、より汎用的な関数
json_encode() + file_put_contents()JSON形式でのファイル出力フォーマットがJSONである点が異なる

よくある落とし穴(注意点)

  1. yaml拡張がインストールされていないと即座にエラーになる yaml_emit() と同様、この関数もyaml拡張が有効になっていることが前提です。事前に extension_loaded('yaml') で確認する習慣をつけましょう(例1を参照)。
  2. 書き込み先ディレクトリが存在しないと失敗する yaml_emit_file() は、指定したパスの親ディレクトリが存在しない場合、自動的にディレクトリを作成してはくれません。事前に is_dir() と mkdir() を使ってディレクトリの存在を保証する必要があります(例3を参照)。
  3. 戻り値のチェックを省略する ファイルの書き込み権限がない、ディスク容量が不足しているなどの理由で書き込みに失敗した場合、戻り値は false になります。この確認を怠ると、実際にはファイルが更新されていないにもかかわらず処理が正常に進んでしまう可能性があります(例2を参照)。
  4. 書き込み中の中断によるファイル破損リスク 大きなデータを書き込んでいる最中にプロセスが中断されると、不完全なYAMLファイルが残ってしまう可能性があります。重要な設定ファイルを扱う場合は、一時ファイル経由でのアトミックな置き換えを検討しましょう(例5を参照)。
  5. 既存ファイルを無条件に上書きする yaml_emit_file() は、指定したパスに既にファイルが存在する場合、確認なしに上書きします。誤って重要な設定ファイルを消してしまわないよう、必要に応じてバックアップを取る仕組みを組み込みましょう(例6を参照)。

まとめ

観点まとめ
何をする関数かPHPの値をYAML形式に変換し、そのまま指定したファイルパスに書き込む
主な用途設定ファイルの自動生成、環境別設定ファイルの一括出力
yaml_emit()との違い文字列を経由せず、変換と保存を1回の呼び出しで完結できる
前提条件yaml PECL拡張が有効になっていること(yaml_emit()と共通)
注意点ディレクトリの事前作成が必要、戻り値チェックの徹底、無条件上書きへの対策

yaml_emit_file() は、yaml_emit() と file_put_contents() を組み合わせる典型的なパターンを簡潔に書けるようにした、利便性重視の関数です。単純なファイル出力であれば積極的に活用し、出力前に文字列としての加工が必要な場合は yaml_emit() を使うという使い分けを意識しましょう。

タイトルとURLをコピーしました