5月になり、晴れた日には暑さを感じる日も増えています。PHPの次のマイナーバージョンであるPHP 8.5のリリースマネージャが決定されて開発体制が整い、いよいよ開発が本格化していきます。本連載では、前回に引き続きPHP 8.5で強化される機能について紹介していきます。
PHP 8.5の開発体制が決定
PHPの各バージョンのリリースプロセスでは、ベテラン1名とルーキー2名の合計3名から構成されるリリースマネージャがリリースの指揮・管理を行います。PHP 8.5のリリースマネージャの内、ベテランはPHP 8.2/8.3のリリースマネージャであったPierrick Charron氏に決まっていましたが、今回、投票を経て、ルーキー2名についてもVolker Dusch氏とDaniel Scherzer氏に決まりました。
今後、計画通りにα版、β版、リリース候補(RC)版をリリースしていく予定です。新機能の導入に向けた提案・投票が複数現時点で行われていますが、8月12日にはフィーチャーフリーズが宣言される計画ですので、その頃には、機能が確定される予定です。以下、PHP8.5で実装される予定の主な機能について順番に紹介していきます。
PHP定数でアノテーションが利用可能に
PHP8では、コード解析ツールなどで解釈可能なメタデータを埋め込む機能であるアノテーションが利用可能になっています。PHPのアノテーションは、クラス(プロパティ、メソッド、定数)、関数、関数・メソッドの引数で利用可能でしたが、(クラス定数ではない通常の)定数はサポートされていませんでした。PHP 8.5では、定数においてアノテーションが利用可能になります。以下に早速簡単な例を見てみましょう。
<?php
#[\MyAttribute]
const Example1 = 1;
#[\Deprecated]
const Example2 = 2;
$reflection = new ReflectionConstant(‘Example1’);
var_dump($reflection->getAttributes());
ここでは、Example1、Example2という二つの定数を定義しています。各定数にはアノテーションが付与されています。なお、PHPでは、const Example1=1、 Example2=2; のように、定数を一度に複数定義することが可能ですが、この場合、アノテーションを付与することができないことに注意してください(致命的エラーを発生します)。
8行目で定数名を引数に指定してReflectionConstantクラスのインスタンスを生成、getAttributes()メソッドで属性を取得すると、以下のようにReflectionAttributeオブジェクトのプロパティ変数nameの値として、定数に付与された属性名(MyAttribute)が取得されます。
array(1) {
[0]=>
object(ReflectionAttribute)#2 (1) {
[“name”]=>
string(11) “MyAttribute”
}
}
PHP 8.4以降では、廃止対象であることをマークする\Deprecatedアノテーションが利用可能です。上記のExample2定数にこのアノテーションが付与されています。
PHP 8.5以降のReflectionConstantクラスでは、isDeprecatedメソッドが追加されており、\Deprecatedアノテーションが当該定数に付与されているかについて調べることができます。
var_dump((new ReflectionConstant(‘Example1’))->isDeprecated());
var_dump((new ReflectionConstant(‘Example2’))->isDeprecated());
この部分の出力は以下となります。Example1定数にはDeprecatedアノテーションが付与されていないため、isDeprecated()メソッドの戻り値はfalseとなります。一方、Example2定数にはDeprecatedアノテーションが付与されているため、isDeprecatedクラスの戻り値はtrueとなります。
bool(false)
bool(true)
エラー・例外ハンドラ取得が可能に
PHPではエラー・例外をハンドルする処理をユーザが独自にカスタム定義することが可能です。ユーザによる定義を行う際はハンドラ関数を定義し、エラー・例外のハンドラをset_error_handler()、set_exception_handler()関数で指定します。この際、現在設定されているハンドラ関数へのリンクが戻り値として返されます。しかし、現在設定されているハンドラ関数を取得する関数自体はサポートされていませんでした。PHP 8.5では、get_error_handler()、get_exception_handler()関数が追加され、それぞれ、現在設定されているエラー・例外のハンドラ関数を取得できるようになります。では、早速簡単なサンプルコードをみてみましょう。
まず、エラー・例外のハンドラ関数を定義します。なお、エラー処理自体は実装しておらず、関数が取得できるかのみを確認します。
<?php
function foo() {}
class C {
function handle() {}
static function handleStatic() {}
}
この例では、通常の関数foo()、クラスCに実装されたメソッドhandle()、スタティックメソッドhandleStatic()を定義しています。get_exception_handler()の使用例は、以下のようになります。
set_error_handler(‘foo’);
var_dump(get_error_handler() === ‘foo’); // bool(true)set_error_handler([$c = new C()、 ‘handle’]);
var_dump(get_error_handler() === [$c、 ‘handle’]); // bool(true)set_error_handler([C::class、 ‘handleStatic’]);
var_dump(get_error_handler() === [C::class、 ‘handleStatic’]); // bool(true)
まず、先頭2行では、関数fooをset_error_handler()によりエラーハンドラーに設定、get_error_handler()でハンドルを取得しています。関数を指定した場合、その関数名の文字列が返されます。
次の2行では、クラスCのメソッドhandle()で同様の確認を行っています。クラスの場合、クラスのインスタンスとメソッド名が配列として取得されます。
さらに次の2行では、クラスのスタティックメソッドの場合について確認しています。この場合も同じく配列が返されますが、最初の要素として「クラス名::class」のようにスタティッククラスオブジェクトが取得されます。
一方、例外ハンドラを取得する場合は、get_exception_handler()を用います。
set_exception_handler(‘foo’);
var_dump(get_exception_handler() === ‘foo’); // bool(true)
ここでは、関数foo()をset_exception_handler()により指定し、get_exception_handler()で取得しています。クラスのメソッド(スタティックメソッド)の場合も同様に取得することができます。
致命的エラーのバックトレースを表示
PHPでは、エラー発生時にエラーの内容をメッセージとして表示することができます。ただし、従来のエラーメッセージは必ずしもエラーの詳細な内容を表示してくれるものではありませんでした。
例えば、以下のように再帰的に実行される関数recurse()を実行し、最大実行時間エラーで致命的エラーが発生する場合をみてみましょう。ここでは、set_time_limit()により最大実行時間を1秒に設定します。このコードでは無限にループ処理が実行されますが、ループ処理の内部でusleep()関数により0.1秒の遅延をかけているため、再帰処理の途中で実行時間エラーを発生するはずです。
<?php
set_time_limit(1);
function recurse() {
usleep(100000);
recurse();
}recurse();
PHP 8.4までのバージョンでは、以下のようなエラーが発生します。
PHP Fatal error: Maximum execution time of 1 second exceeded in t85_5。php on line 10
最大実行エラーのエラーが発生したことがわかりますが、再帰的に実行されている部分のどこでエラーが発生したかなどの詳細な情報は表示されません。
PHP 8.5では、致命的エラーが発生した際にスタックトレースを表示する機能が追加されます。上記のコードをPHP 8.5で実行すると、以下のように致命的エラーの内容が出力されます。
PHP Fatal error: Maximum execution time of 1 second exceeded in t85_5。php on line 10
Stack trace:
#0 t85_5。php(10): usleep(100000)
#1 t85_5。php(11): recurse()
#2 t85_5。php(11): recurse()
#3 t85_5。php(11): recurse()
#4 t85_5。php(11): recurse()
#5 t85_5。php(11): recurse()
#6 t85_5。php(11): recurse()
#7 t85_5。php(11): recurse()
#8 t85_5。php(11): recurse()
#9 t85_5。php(11): recurse()
#10 t85_5。php(14): recurse()
#11 {main}
スタック・トレースに関する情報が表示されており、10回のループ処理が再帰的に実行されたことがわかります。再帰処理のエラーのデバッグは容易ではないため、このようなバックトレース機能がサポートされたことにより、PHP開発がより便利になることが期待されます。
今回は、次期マイナーバージョンであるPHP 8.5に関する情報として、リリースに向けた開発体制、変更点のいくつかを紹介しました。今回紹介した機能以外にも新たな機能の導入や変更が予定されており、次回以降で紹介する予定です。