あっぽログ
← 記事一覧に戻る

PHPのFiberで並行処理を理解する:軽量スレッドで非同期風プログラミングを実現する

PHPのFiberとは?

PHP 8.1で正式に導入された**Fiber(ファイバー)**は、PHPに「軽量スレッド」の概念をもたらす機能です。

従来のPHPは基本的に同期的・逐次的に処理が進みます。ある関数が時間のかかる処理を行っている間、他の処理は待つしかありませんでした。Fiberを使うと、処理を途中で**一時停止(suspend)し、他の処理に切り替えて、あとで再開(resume)**するという流れが実現できます。

FiberはOSのスレッドとは異なり、切り替えのタイミングはプログラマが明示的にコントロールします。そのためコルーチンとも呼ばれます。


Fiberの基本的な使い方

まずはもっともシンプルなFiberのコード例を見てみましょう。

<?php

$fiber = new Fiber(function (): void {
    echo "Fiber: 処理を開始します\n";

    $value = Fiber::suspend('最初のsuspend');

    echo "Fiber: resumeで受け取った値 → {$value}\n";

    Fiber::suspend('2回目のsuspend');

    echo "Fiber: 処理を終了します\n";
});

// Fiberを開始する
$result1 = $fiber->start();
echo "メイン: Fiberからの戻り値 → {$result1}\n";

// Fiberを再開し、値を渡す
$result2 = $fiber->resume('こんにちは');
echo "メイン: Fiberからの戻り値 → {$result2}\n";

// 最後まで実行させる
$fiber->resume();

実行結果:

Fiber: 処理を開始します
メイン: Fiberからの戻り値 → 最初のsuspend
Fiber: resumeで受け取った値 → こんにちは
メイン: Fiberからの戻り値 → 2回目のsuspend
Fiber: 処理を終了します

処理の流れを整理する

メソッド説明
new Fiber(callable)Fiberを作成する(まだ実行されない)
$fiber->start(...$args)Fiberの実行を開始する
Fiber::suspend($value)Fiberを一時停止し、呼び出し元に値を返す
$fiber->resume($value)Fiberを再開し、suspendの戻り値として値を渡す
$fiber->getReturn()Fiberが終了したあとの戻り値を取得する

Fiberの状態を確認する

Fiberにはいくつかの状態があり、メソッドで確認できます。

<?php

$fiber = new Fiber(function (): string {
    Fiber::suspend();
    return 'Fiberの戻り値';
});

var_dump($fiber->isStarted());    // bool(false)
var_dump($fiber->isSuspended());  // bool(false)
var_dump($fiber->isRunning());    // bool(false)
var_dump($fiber->isTerminated()); // bool(false)

$fiber->start();

var_dump($fiber->isStarted());    // bool(true)
var_dump($fiber->isSuspended());  // bool(true)

$fiber->resume();

var_dump($fiber->isTerminated()); // bool(true)
var_dump($fiber->getReturn());    // string(12) "Fiberの戻り値"

状態を把握しておくと、複数のFiberを管理するときに「このFiberはまだ動いているか?」「すでに終わったか?」を安全に判断できます。


複数のFiberを切り替える実例

Fiberの真価は複数の処理を協調動作させる場面で発揮されます。次の例では、2つのFiberが交互に処理を進める様子を示します。

<?php

function makeWorker(string $name, int $steps): Fiber
{
    return new Fiber(function () use ($name, $steps): void {
        for ($i = 1; $i <= $steps; $i++) {
            echo "{$name}: ステップ {$i}\n";
            Fiber::suspend();
        }
    });
}

$fiberA = makeWorker('Worker-A', 3);
$fiberB = makeWorker('Worker-B', 3);

// 両方のFiberをスケジューリングする
$fibers = [$fiberA, $fiberB];

// 最初にstartを呼ぶ
foreach ($fibers as $fiber) {
    $fiber->start();
}

// まだ終わっていないFiberをresumeし続ける
while (true) {
    $running = array_filter($fibers, fn($f) => !$f->isTerminated());
    if (empty($running)) {
        break;
    }
    foreach ($running as $fiber) {
        $fiber->resume();
    }
}

実行結果:

Worker-A: ステップ 1
Worker-B: ステップ 1
Worker-A: ステップ 2
Worker-B: ステップ 2
Worker-A: ステップ 3
Worker-B: ステップ 3

このように、シングルスレッドのまま複数の処理を交互に進めることができます。これが「協調的マルチタスク」の基本的な考え方です。


Fiberを使う際の注意点

✅ Fiberはマルチスレッドではない

FiberはOSレベルのスレッドを使いません。あくまで1つのスレッドの中で処理を切り替える仕組みです。本当の並列実行(CPUコアを複数使う)は実現しません。

✅ 非同期ライブラリと組み合わせるのが実践的

実際のプロダクションでは、Fiberを直接使うよりReactPHPRevoltなどのイベントループライブラリと組み合わせて使うケースが多いです。これらのライブラリは内部的にFiberを活用して、I/O待ちの間に他の処理を進めるといった実装をしています。

✅ PHP8.1以上が必要

FiberはPHP 8.1から利用可能です。本番環境のPHPバージョンを必ず確認しましょう。


まとめ

今回学んだFiberのポイントを整理します。

  • new Fiber(callable) でFiberを作成し、start() で開始する
  • Fiber::suspend($value) で処理を一時停止し、呼び出し元に値を返す
  • $fiber->resume($value) でFiberを再開し、suspend の戻り値として値を渡す
  • isStarted() / isSuspended() / isTerminated() で状態を確認できる
  • 複数のFiberを自前でスケジューリングすることで、協調的な並行処理が書ける

FiberはPHPの非同期・並行処理の世界を広げる重要な機能です。まずは今回のコード例を手元で動かしながら、処理の流れを体で覚えることをおすすめします。

← 記事一覧に戻る