ファイバー (PHP 8.1)
CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 60/91。
Fiberは、コード実行を中断できるようにするPHP 8.1の機能です。最初から最後まで実行される通常の関数とは異なり、ファイバーは実行途中で自身を一時停止し、後から再開することができます。その際、一時停止の間も状態が保持されます。
Fiber class に callable を渡して fiber を作成し、start() で開始します:
<?php
$fiber = new Fiber(function(): void {
echo "Step 1\n";
Fiber::suspend();
echo "Step 2\n";
});
$fiber->start();
echo "Between steps\n";
$fiber->resume();
出力:
Step 1
Between steps
Step 2ファイバーは Fiber::suspend() に達するまで実行され、その後コントロールがメインコードに戻ります。resume() を呼び出すと、一時停止した場所から実行が再開されます。
Fiber は中断時および再開時に値を渡すこともできます:
<?php
$fiber = new Fiber(function(): string {
$value = Fiber::suspend("paused");
return "Received: $value";
});
$suspended = $fiber->start();
echo "$suspended\n";
$result = $fiber->resume("hello");
echo $result;
出力:
paused
Received: helloFiber は非同期 PHP フレームワークの基礎です。ほとんどのアプリケーションで直接使用することはありませんが、その仕組みを理解しておくと、HTTP リクエストやデータベースクエリなどの並列処理をブロックなしで実行する非同期ライブラリを扱う際に役立ちます。
チャレンジ
簡単ファイバーとメインコードの間でデータをやり取りしながら、実行を停止および再開する方法を示すタスクスケジューラを作成しましょう。タスクを中断して、その間に他の処理を行えるシステムを構築します。
コードは2つのファイルに分けて整理します:
TaskRunner.php— タスクを実行するためのファイバー機能をラップするTaskRunnerクラスを作成します。このクラスの仕様は以下の通りです:Fiberインスタンスを保持するprivateプロパティを持つこと- コンストラクタのプロパティプロモーションを使用して、コンストラクタでタスク名(文字列)を受け取ること
- 指定された
callableで新しい Fiber を作成して保存するcreateTask(callable $task)メソッドを持つこと - ファイバーを開始し、ファイバーが中断(suspend)したときの値(または最終的な返り値)を返す
start()メソッドを持つこと - 指定された値でファイバーを再開し、次に中断されたときの値(または最終的な返り値)を返す
continue(mixed $value)メソッドを持つこと - ファイバーが終了したかどうかを返す
isFinished(): boolメソッドを持つこと
main.php— TaskRunner ファイルを読み込みます。入力としてタスク名とファイバーに送信するメッセージの2つを受け取ります。指定されたタスク名で
TaskRunnerを作成し、createTask()を使用して以下の処理を行うタスクを定義します:- 最初に文字列
"Waiting for input"を伴って中断(suspend)する - 再開されたときに値を受け取る
"Completed: [received value]"を返す
タスクを開始し、最初に中断したときに返される値を表示します。次に、ファイバーの中断中に処理が行われていることを示すために
"Processing..."を表示します。最後に、入力されたメッセージを渡してファイバーを再開(continue)し、最終結果を表示します。- 最初に文字列
このチャレンジは、ファイバーによって協調的マルチタスクがどのように実現されるかを示しています。タスクは適切なタイミングで自身を停止し、メインコードが他の処理を行い、新しいデータとともにタスクを再開します。ファイバーは状態を維持し、中断したまさにその場所から再開します。
自分で試してみよう
<?php
require_once 'TaskRunner.php';
// 入力を読み取る
$taskName = trim(fgets(STDIN));
$message = trim(fgets(STDIN));
// TODO: 指定されたタスク名で TaskRunner を作成する
// TODO: createTask() を使って次のタスクを定義する:
// 1. First suspends with the string "Waiting for input"
// 2. 再開時に値を受け取る
// 3. "Completed: [received value]" を返す
// TODO: タスクを開始し、最初に中断したときに返す内容を出力する
// TODO: ファイバーの一時停止の間に処理が進んでいることを示すため "Processing..." を出力する
// TODO: メッセージ入力を渡してファイバーを続行する
// TODO: 最終結果を出力する
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
10オブジェクト指向の高度な概念
コンポジション vs 継承依存性の注入 (Dependency Injection)匿名クラスEnum (PHP 8.1)ファイバー (PHP 8.1)オブジェクトのクローン徹底解説ジェネレータとイテレータ