PHPの最新状況:PHP 8.1の開発が進む(第18回)

PHP

廣川類

次期アップデートとなるPHP 8.1の開発が順調に進行中で、その主要機能としてFiberが追加されます。Fiberは非同期処理を手助けする仕組みで、複数のタスクを並行して処理してユーザの待ち時間を減らし、利便性を向上させることができます。しかし、非同期処理は実装が難しく、バグを引き起こす可能性もあるため、フレームワーク等の高位機能を利用し、間接的にこの機能を利用することが予想されます。この記事では、PHP 8.1の新機能Fiberの具体的な使用例を示しています。

季節はすっかり夏となりましたが,次期マイナーバージョンアップとなるPHPバージョン8.1の開発は計画通り順調に進んでおり,6月10日にアルファ1版がリリースされています.本稿では,前回に引き続きPHP 8.1における変更点について紹介します.

PHP 8.1の開発スケジュール

PHP 8.1は,6月10日にアルファ1版がリリースされて以降,正式なリリースサイクルに入っています.この後,7月20にフィーチャーフリーズが行われた後,7~8月にベータ版,9~11月にリリース候補版のリリースが予定されてています.開発が順調にいくと,正式版が11月25日にリリースされる予定です.本稿執筆時点(6月)では,7月のフィーチャーフリーズに向けて,ほぼ機能が出そろっています.

本稿では,追加される主要な機能としてFiberを紹介します.

同期処理と非同期処理

 アプリケーションにおいて複数の処理(タスク)を実行する際,通常,複数のタスクが決められた順番で逐次実行されます.このような処理方式を同期処理と言います.同期処理のメリットはプログラムの処理の流れが簡潔で把握しやすいことですが,一連のタスクの実行処理が全て完了するまでユーザは待つ必要があるため,ユーザ利便性を損なうリスクがあります.一方,非同期処理においては,一つのタスクを実行している際に,他のタスクを実行できます.非同期処理の有名な例は,Webブラウザ上で動作するJavaScriptのAjax (Asynchronous JavaScript and XML)やサーバ側JavaScript環境で動作するNode.jsです.非同期処理を活用すると,データベースでの検索処理などの比較的重い処理を行っている際中でもユーザによる他の操作を可能とするなど,タスク処理中のユーザの待ち時間を減らし,利便性を向上させることができます.ただし,非同期処理のプログラム処理の把握は同期処理に比べると難しくなり,設計・実装がうまく行われていない場合,バグを発生したり,処理完了までの速度が遅くなる場合があります.

 非同期処理を記述する際には,イベント発生をトリガーとしたコールバック関数を利用して,時間を要する処理などを切り出すという実装方法がとられます.ただし,従来のコールバック関数の仕組みでは,コールバック関数がネストした場合など,スタック管理の複雑さに関する問題を発生する懸念があります.

ファイバーによる非同期処理の導入

 ファイバー(Fiber)は,協調マルチタスク処理により複数タスクの非同期処理を簡易的に実現する仕組みです.ファイバーはコルーチン(coroutine)またグリーンスレッドとも呼ばれています.ファイバーは,通常のスレッドと同じくメインタスクとアドレス空間を共用します.一方,スレッドがプリエンプティブなマルチタスクを行うのに対して,ファイバーでは協調マルチタスクによるタスク切替制御を行います.つまり,タスク切替処理を行う際,スレッドでは時間スロット毎に実行環境(PHP仮想マシン)が優先順位に基づくタスク実行制御を行いますが,協調マルチタスクにおいては,タスク(ファイバー)自体が実行権限を実行環境に戻すことにより,より簡易的な実行制御が行われます.

 

 PHP 8.1では,Fiberクラスにより協調マルチタスク処理機能を実現します.図1に従来の逐次処理とファイバーにとる協調マルチタスク処理の比較を示します.

  1. コールバック関数を指定してFiberクラスのインスタンスを作成します.
  2. startメソッドをコールすると,ファイバーの処理が開始されます.
  3. 処理の中断が可能な任意の場所でsuspendメソッドをコールし,メインタスクに実行権限を戻します.suspendメソッドがコールされると,startメソッド(またはresumeメソッド)をコールした時点から実行が再開されます.
  4. suspendメソッドの引数には,メインタスクに渡す値を指定できます.戻り値はstartメソッド(またはresumeメソッド)の戻り値となります.
  5. メインタスクにおいては,任意のタイミングでresumeメソッドをコールして,ファイバーの処理を再開させることができます.その際,引数を指定すると,suspendメソッドの戻り値として取得されます.
  6. 複数のファイバーを同時に宣言できますが,同時に複数のファイバーを実行することはできません.

季節はすっかり夏となりましたが,次期マイナーバージョンアップとなるPHPバージョン8.1の開発は計画通り順調に進んでおり,6月10日にアルファ1版がリリースされています.本稿では,前回に引き続きPHP 8.1における変更点について紹介します.

PHP 8.1の開発スケジュール

PHP 8.1は,6月10日にアルファ1版がリリースされて以降,正式なリリースサイクルに入っています.この後,7月20にフィーチャーフリーズが行われた後,7~8月にベータ版,9~11月にリリース候補版のリリースが予定されてています.開発が順調にいくと,正式版が11月25日にリリースされる予定です.本稿執筆時点(6月)では,7月のフィーチャーフリーズに向けて,ほぼ機能が出そろっています.

本稿では,追加される主要な機能としてFiberを紹介します.

同期処理と非同期処理

 アプリケーションにおいて複数の処理(タスク)を実行する際,通常,複数のタスクが決められた順番で逐次実行されます.このような処理方式を同期処理と言います.同期処理のメリットはプログラムの処理の流れが簡潔で把握しやすいことですが,一連のタスクの実行処理が全て完了するまでユーザは待つ必要があるため,ユーザ利便性を損なうリスクがあります.一方,非同期処理においては,一つのタスクを実行している際に,他のタスクを実行できます.非同期処理の有名な例は,Webブラウザ上で動作するJavaScriptのAjax (Asynchronous JavaScript and XML)やサーバ側JavaScript環境で動作するNode.jsです.非同期処理を活用すると,データベースでの検索処理などの比較的重い処理を行っている際中でもユーザによる他の操作を可能とするなど,タスク処理中のユーザの待ち時間を減らし,利便性を向上させることができます.ただし,非同期処理のプログラム処理の把握は同期処理に比べると難しくなり,設計・実装がうまく行われていない場合,バグを発生したり,処理完了までの速度が遅くなる場合があります.

 非同期処理を記述する際には,イベント発生をトリガーとしたコールバック関数を利用して,時間を要する処理などを切り出すという実装方法がとられます.ただし,従来のコールバック関数の仕組みでは,コールバック関数がネストした場合など,スタック管理の複雑さに関する問題を発生する懸念があります.

ファイバーによる非同期処理の導入

 ファイバー(Fiber)は,協調マルチタスク処理により複数タスクの非同期処理を簡易的に実現する仕組みです.ファイバーはコルーチン(coroutine)またグリーンスレッドとも呼ばれています.ファイバーは,通常のスレッドと同じくメインタスクとアドレス空間を共用します.一方,スレッドがプリエンプティブなマルチタスクを行うのに対して,ファイバーでは協調マルチタスクによるタスク切替制御を行います.つまり,タスク切替処理を行う際,スレッドでは時間スロット毎に実行環境(PHP仮想マシン)が優先順位に基づくタスク実行制御を行いますが,協調マルチタスクにおいては,タスク(ファイバー)自体が実行権限を実行環境に戻すことにより,より簡易的な実行制御が行われます.

 

 PHP 8.1では,Fiberクラスにより協調マルチタスク処理機能を実現します.図1に従来の逐次処理とファイバーにとる協調マルチタスク処理の比較を示します.

  1. コールバック関数を指定してFiberクラスのインスタンスを作成します.
  2. startメソッドをコールすると,ファイバーの処理が開始されます.
  3. 処理の中断が可能な任意の場所でsuspendメソッドをコールし,メインタスクに実行権限を戻します.suspendメソッドがコールされると,startメソッド(またはresumeメソッド)をコールした時点から実行が再開されます.
  4. suspendメソッドの引数には,メインタスクに渡す値を指定できます.戻り値はstartメソッド(またはresumeメソッド)の戻り値となります.
  5. メインタスクにおいては,任意のタイミングでresumeメソッドをコールして,ファイバーの処理を再開させることができます.その際,引数を指定すると,suspendメソッドの戻り値として取得されます.
  6. 複数のファイバーを同時に宣言できますが,同時に複数のファイバーを実行することはできません.

図1 従来の逐次処理とファイバーによる協調マルチタスク処理

ファイバーの実行例

 協調マルチタスクを実現する際,各タスクでは処理の中断が可能な任意の場所でFiberクラスのsuspend()メソッドをコールし,仮想マシンに実行権限を戻します.以下にファイバーの簡単な使用例を示します.

––

<?php

$fiber = new Fiber(function () {

    echo “中断します\n”;

    Fiber::suspend();

    echo “再開しました\n”;

});

$fiber->start();

echo “再開します\n”;

$fiber->resume();

—-

この例の出力は以下となります.

中断します

再開します

再開しました

まず,Fiberクラスのインスタンスを作成します(2行目).ここでは,コールバック関数を無名関数として定義して,指定しています.次に8行目でstartメソッドをコールすることにより,ファイバーが実行されます.この例では4行目ですぐにsuspendメソッドをコールし,処理を中断しています.処理が中断すると,メインタスクに処理が戻り,startメソッドの直後から実行が再開されます.この後,10行目でresumeメソッドをコールします.これにより,ファイバーの実行処理が再開され,suspendメソッド(4行目)の直後から実行が行われます.

ファイバーに例外を投げる

 resumeメソッドの代わりにthrowメソッドにより例外をファイバーに投げることも可能で,この場合もsuspendメソッドの直後から実行が再開されます.以下に例外を発生する簡単なコードの例を示します.

 

––

<?php

$fiber = new Fiber(function () {

 try {

       Fiber::suspend();

    } catch (Exception $e) {

       echo $e->getMessage();

    }

    echo “再開しました\n”;

});

$fiber->start();

$fiber->throw(new Exception(“例外発生\n”));

—-

 この例の出力は,以下となります.

例外発生

再開しました.

 メインタスクでは,12行目でファイバーに例外処理を投げています.コールバック関数の中では,tryブロックの中でsuspendメソッドをコールし,例外を受信するとcatchブロックの中のコードが実行されます.

ファイバーとの値の授受

 非同期処理においては,ファイバーの動作状況をモニタしたり,ファイバーに値を指定して動作を制御することが必要となります.これにより,例えば,時間のかかるファイルのダウンロードの進捗状況を表示したりすることが可能となります.PHPのFiberでは,このようなメインタスクとファイバーの値の受け渡しの方法が定義されており,ファイバーからメインタスクに値を渡す際にはsuspendメソッドの引数,メインタスクからファイバーに値を指定する際にはresumeメソッドの引数に指定します.これらの値は,start,resume,suspendメソッドの戻り値として取得できます.以下に簡単な例を示します.

––

<?php

$fiber = new Fiber(function (): void {

    $id = Fiber::suspend(‘taro’);

    echo “ID: “, $id, “\n”;

});

$name = $fiber->start();

echo “氏名: $name\n”;

$fiber->resume(‘1200’);

—-

この例の出力は以下となります.

氏名: taro

ID: 1200

 この例では,suspendメソッドをコールする際に引数”taro”を指定しています(3行目).この値は,startメソッドの戻り値として取得されます(7行目).一方,resumeメソッドに引数(1200)を指定し,

ファイバーに値を渡しています(9行目).

ファイバーの実用的な利用

 非同期処理の実装は,PHPにおいて期待されていた機能の一つであり,今後,活用事例が広まっていくと予想されます.ただし,今回実装されたファイバー機能は非同期処理の基本的な仕組みであり,使いこなすことが難しいため,多くのユーザーはSymfonyやLaravelのようなフレームワーク等に含まれる高位の機能(例えば状況モニタなどの非同期処理をサポートするファイルダウンロード機能)を利用することで,間接的にこの機能を利用していくようになると思われます.

 すでにamphpやReactPHPのような低レベルフレームワークではファイバーの機能の取り込みが開始されており,Symfonyのような高レベルフレームワークにおける対応も今後進むと期待されます.

 PHPで非同期処理が可能となることでPHPの応用範囲が広がる可能性があり,例えば,WebサーバーやWebSocketに関する処理を効率的にPHPで記述することができるようになると期待されます.

 現在のファイバーの実装では,同時に実行されるファイバーの数は1つに制限されていますが,人気のスクリプト言語Goのチャネルのような仕組みが今後導入され,PHPの将来のバージョンで解決される可能性もあります.また,タスク間の値の受け渡しにおいても自由度の向上が期待されます.  本稿では,PHP 8.1の新機能であるファイバーについて紹介しました.次回もPHP 8.1のその他の変更点について紹介します

季節はすっかり夏となりましたが,次期マイナーバージョンアップとなるPHPバージョン8.1の開発は計画通り順調に進んでおり,6月10日にアルファ1版がリリースされています.本稿では,前回に引き続きPHP 8.1における変更点について紹介します.

PHP 8.1の開発スケジュール

PHP 8.1は,6月10日にアルファ1版がリリースされて以降,正式なリリースサイクルに入っています.この後,7月20にフィーチャーフリーズが行われた後,7~8月にベータ版,9~11月にリリース候補版のリリースが予定されてています.開発が順調にいくと,正式版が11月25日にリリースされる予定です.本稿執筆時点(6月)では,7月のフィーチャーフリーズに向けて,ほぼ機能が出そろっています.

本稿では,追加される主要な機能としてFiberを紹介します.

同期処理と非同期処理

 アプリケーションにおいて複数の処理(タスク)を実行する際,通常,複数のタスクが決められた順番で逐次実行されます.このような処理方式を同期処理と言います.同期処理のメリットはプログラムの処理の流れが簡潔で把握しやすいことですが,一連のタスクの実行処理が全て完了するまでユーザは待つ必要があるため,ユーザ利便性を損なうリスクがあります.一方,非同期処理においては,一つのタスクを実行している際に,他のタスクを実行できます.非同期処理の有名な例は,Webブラウザ上で動作するJavaScriptのAjax (Asynchronous JavaScript and XML)やサーバ側JavaScript環境で動作するNode.jsです.非同期処理を活用すると,データベースでの検索処理などの比較的重い処理を行っている際中でもユーザによる他の操作を可能とするなど,タスク処理中のユーザの待ち時間を減らし,利便性を向上させることができます.ただし,非同期処理のプログラム処理の把握は同期処理に比べると難しくなり,設計・実装がうまく行われていない場合,バグを発生したり,処理完了までの速度が遅くなる場合があります.

 非同期処理を記述する際には,イベント発生をトリガーとしたコールバック関数を利用して,時間を要する処理などを切り出すという実装方法がとられます.ただし,従来のコールバック関数の仕組みでは,コールバック関数がネストした場合など,スタック管理の複雑さに関する問題を発生する懸念があります.

ファイバーによる非同期処理の導入

 ファイバー(Fiber)は,協調マルチタスク処理により複数タスクの非同期処理を簡易的に実現する仕組みです.ファイバーはコルーチン(coroutine)またグリーンスレッドとも呼ばれています.ファイバーは,通常のスレッドと同じくメインタスクとアドレス空間を共用します.一方,スレッドがプリエンプティブなマルチタスクを行うのに対して,ファイバーでは協調マルチタスクによるタスク切替制御を行います.つまり,タスク切替処理を行う際,スレッドでは時間スロット毎に実行環境(PHP仮想マシン)が優先順位に基づくタスク実行制御を行いますが,協調マルチタスクにおいては,タスク(ファイバー)自体が実行権限を実行環境に戻すことにより,より簡易的な実行制御が行われます.

 

 PHP 8.1では,Fiberクラスにより協調マルチタスク処理機能を実現します.図1に従来の逐次処理とファイバーにとる協調マルチタスク処理の比較を示します.

  1. コールバック関数を指定してFiberクラスのインスタンスを作成します.
  2. startメソッドをコールすると,ファイバーの処理が開始されます.
  3. 処理の中断が可能な任意の場所でsuspendメソッドをコールし,メインタスクに実行権限を戻します.suspendメソッドがコールされると,startメソッド(またはresumeメソッド)をコールした時点から実行が再開されます.
  4. suspendメソッドの引数には,メインタスクに渡す値を指定できます.戻り値はstartメソッド(またはresumeメソッド)の戻り値となります.
  5. メインタスクにおいては,任意のタイミングでresumeメソッドをコールして,ファイバーの処理を再開させることができます.その際,引数を指定すると,suspendメソッドの戻り値として取得されます.
  6. 複数のファイバーを同時に宣言できますが,同時に複数のファイバーを実行することはできません.
図1 従来の逐次処理とファイバーによる協調マルチタスク処理

ファイバーの実行例

 協調マルチタスクを実現する際,各タスクでは処理の中断が可能な任意の場所でFiberクラスのsuspend()メソッドをコールし,仮想マシンに実行権限を戻します.以下にファイバーの簡単な使用例を示します.

––

<?php

$fiber = new Fiber(function () {

    echo “中断します\n”;

    Fiber::suspend();

    echo “再開しました\n”;

});

$fiber->start();

echo “再開します\n”;

$fiber->resume();

—-

この例の出力は以下となります.

中断します

再開します

再開しました

まず,Fiberクラスのインスタンスを作成します(2行目).ここでは,コールバック関数を無名関数として定義して,指定しています.次に8行目でstartメソッドをコールすることにより,ファイバーが実行されます.この例では4行目ですぐにsuspendメソッドをコールし,処理を中断しています.処理が中断すると,メインタスクに処理が戻り,startメソッドの直後から実行が再開されます.この後,10行目でresumeメソッドをコールします.これにより,ファイバーの実行処理が再開され,suspendメソッド(4行目)の直後から実行が行われます.

ファイバーに例外を投げる

 resumeメソッドの代わりにthrowメソッドにより例外をファイバーに投げることも可能で,この場合もsuspendメソッドの直後から実行が再開されます.以下に例外を発生する簡単なコードの例を示します.

 

––

<?php

$fiber = new Fiber(function () {

 try {

       Fiber::suspend();

    } catch (Exception $e) {

       echo $e->getMessage();

    }

    echo “再開しました\n”;

});

$fiber->start();

$fiber->throw(new Exception(“例外発生\n”));

—-

 この例の出力は,以下となります.

例外発生

再開しました.

 メインタスクでは,12行目でファイバーに例外処理を投げています.コールバック関数の中では,tryブロックの中でsuspendメソッドをコールし,例外を受信するとcatchブロックの中のコードが実行されます.

ファイバーとの値の授受

 非同期処理においては,ファイバーの動作状況をモニタしたり,ファイバーに値を指定して動作を制御することが必要となります.これにより,例えば,時間のかかるファイルのダウンロードの進捗状況を表示したりすることが可能となります.PHPのFiberでは,このようなメインタスクとファイバーの値の受け渡しの方法が定義されており,ファイバーからメインタスクに値を渡す際にはsuspendメソッドの引数,メインタスクからファイバーに値を指定する際にはresumeメソッドの引数に指定します.これらの値は,start,resume,suspendメソッドの戻り値として取得できます.以下に簡単な例を示します.

––

<?php

$fiber = new Fiber(function (): void {

    $id = Fiber::suspend(‘taro’);

    echo “ID: “, $id, “\n”;

});

$name = $fiber->start();

echo “氏名: $name\n”;

$fiber->resume(‘1200’);

—-

この例の出力は以下となります.

氏名: taro

ID: 1200

 この例では,suspendメソッドをコールする際に引数”taro”を指定しています(3行目).この値は,startメソッドの戻り値として取得されます(7行目).一方,resumeメソッドに引数(1200)を指定し,

ファイバーに値を渡しています(9行目).

ファイバーの実用的な利用

 非同期処理の実装は,PHPにおいて期待されていた機能の一つであり,今後,活用事例が広まっていくと予想されます.ただし,今回実装されたファイバー機能は非同期処理の基本的な仕組みであり,使いこなすことが難しいため,多くのユーザーはSymfonyやLaravelのようなフレームワーク等に含まれる高位の機能(例えば状況モニタなどの非同期処理をサポートするファイルダウンロード機能)を利用することで,間接的にこの機能を利用していくようになると思われます.

 すでにamphpやReactPHPのような低レベルフレームワークではファイバーの機能の取り込みが開始されており,Symfonyのような高レベルフレームワークにおける対応も今後進むと期待されます.

 PHPで非同期処理が可能となることでPHPの応用範囲が広がる可能性があり,例えば,WebサーバーやWebSocketに関する処理を効率的にPHPで記述することができるようになると期待されます.

 現在のファイバーの実装では,同時に実行されるファイバーの数は1つに制限されていますが,人気のスクリプト言語Goのチャネルのような仕組みが今後導入され,PHPの将来のバージョンで解決される可能性もあります.また,タスク間の値の受け渡しにおいても自由度の向上が期待されます.

 本稿では,PHP 8.1の新機能であるファイバーについて紹介しました.次回もPHP 8.1のその他の変更点について紹介します.

<< PHPの重鎮である廣川類氏のコラム第17回「PHPの最新状況:PHP開発用サーバーが攻撃を受ける」が掲載されました。PHP重鎮の廣川類氏によるコラム「PHPの最新状況:PHP 8.1の開発がいよいよ最終段階に(第19回)」 >>

関連記事

Webサイト運用の課題解決事例100選 プレゼント

Webサイト運用の課題を弊社プロダクトで解決したお客様にインタビュー取材を行い、100の事例を108ページに及ぶ事例集としてまとめました。

・100事例のWebサイト運用の課題と解決手法、解決後の直接、間接的効果がわかる

・情報通信、 IT、金融、メディア、官公庁、学校などの業種ごとに事例を確認できる

・特集では1社の事例を3ページに渡り背景からシステム構成まで詳解