こんにちは、2019年最初のコラムとなります。本年もよろしくおねがいします。2018年は、PHP 7系の最新版としてバージョン7.3が年末の2018年12月6日にリリースされ、また、PHP 5系の最終版であるバージョン5.6が2018年12月31日をもってサポート期限切れ(End-Of-Life)を迎え、PHP 5からPHP 7への移行という意味で節目の年となりました。本稿では、最近のPHPの更新状況と次版であるバージョン7.4に向けた開発状況を紹介します。
PHPの更新状況
PHP 5系については、従来から2018年いっぱいをもってセキュリティ関連修正を含むサポート期限が切れるとされており、2018年12月6日にリリースされたバージョン5.6.39が最終版となるはずでした。しかし、比較的重要度の高いセキュリティ関連のバグ修正が必要となったため、計画を変更して2019年1月10日にバージョン5.6.40がリリースされました。バージョン5.6.40では、12件のセキュリティ関連の修正が行われています。今回のバージョンがPHP 5系の最終バージョンとなる予定ですが、今後、特に重要度が高いセキュリティ修正が必要となった場合には、修正版がリリースされる可能性があるとphp.netでアナウンスされています。同じ2019年1月10日には、メンテナンス対象のPHPのバージョンであるPHP 7.1、7.2、7.3系においてもセキュリティに関する同様の修正が行われています。なお、PHP 7.0系は昨年の12月をもってサポート期間が終了しており、今回のセキュリティ更新の対象にもなっていないため、特にPHP 7.0系のユーザは注意が必要です。今回修正されたセキュリティ関連の不具合には、mbstringエクステンションのマルチバイト対応正規表現mbregexにおける、複数のバッファオーバーフロー攻撃に関する脆弱性が含まれています。PHP 7系のユーザは、使用するバージョンの最新版に更新することを推奨します。また、PHP 7.0系のユーザは、この機会にPHP 7.1系以上の最新版への更新をお勧めします。PHP 5系のユーザは、PHP 7系への更新を強く推奨しますが、最低でもPHP 5.6.40に更新されることをお勧めします。PHP 7.4の開発状況
PHP 7.3が昨年末にリリースされた後、次のバージョンとしてPHP 7.4の開発が始まっています。PHP 7.4の変更点はまだ確定していませんが、すでに採用される予定の機能のいくつかは決まっています。その中で代表的なものを紹介します。- OpCacheのプリロード機能
- クラスプロパティの型指定追加
PHP 7.4の新機能: OpCacheのプリロード機能
Webアプリケーションの性能を向上させるために最も有効な策の一つとして、オペコードキャッシュがあります。PHPがスクリプトを実行する際の処理の概要を下図に示します。 クライアント(Webブラウザ)からのリクエストを受けると、PHPスクリプトのファイルがファイルシステムから読み込まれ、構文がパースされます。この後、コンパイルされてPHPの仮想マシン上のバイトコードに変換され、実行されます。この処理は、リクエスト処理の度に行われ、PHPスクリプトの実行速度の大きな部分を占めます。オペコードキャッシュは、コンパイル後のバイトコードをメモリ上に保存し、再利用できるようにする機能です。これにより、二回目以降のリクエストに関しては、PHPスクリプトをロード・パース・コンパイルする必要がなくなるため、実行速度が大幅に向上します。従来から、APC、Turck MMCache、Zend OpCacheといったキャッシュエンジンが提供され、使用されてきました。PHP 5.5以降では、PHP本体にOpCacheが組み込まれ、標準機能としてオペコードキャッシュが使用できるようになりました。 PHP 7.4で追加される機能は、Webサーバの起動時に指定したPHPスクリプトのオペコードキャッシュを予めロードできるようにするものです。従来のオペコードキャッシュは、各PHPスクリプトへの最初のリクエストに関しては、スクリプトのロード・コンパイルが行われるため、実行速度の改善が見込めないという課題がありました。PHP 7.4では、設定ファイル(php.ini)の opcache.preload で指定したスクリプトがWebサーバ起動時に自動的に実行され、キャッシュをプリロードすることが可能となります。例として、/var/www/preload.incを読み込む際の設定を以下に示します。 opcache.preload=/var/www/preload.inc ディレクトリ”/var/www/lib”に配置されたPHPスクリプトをロードするpreload.incのコードの例を以下に示します。<?php $path=”/var/www/lib” if ($dh=opendir($path)) { while (($file=readdir($dh))!==false) { $fpath=$path.”/”.$file; if (is_file($fpath) && preg_match(“/\.php$/”,$fpath)) { opcache_compile_file($fpath); } } }プリロード導入の効果は、フレームワークなどスクリプトの数やコードの量が多い場合に大きくなると思われます。プリロード機能の提案(https://wiki.php.net/rfc/preload)においても、Zend Frameworkのベンチマークで30~50%程度の性能改善効果が確認されたと報告されています。
PHP 7.4の新機能: クラスプロパティの型指定追加
“Typed Property 2.0”と名付けられた機能追加提案が、開発者の投票により賛成多数で可決され、PHP 7.4にクラスのプロパティの型指定機能が追加されることになりました。”2.0”と呼ばれているのには理由があり、過去に類似の機能がPHP 7.1用に提案された際には提案が否決されており、今回の提案は見直し版にあたります。具体的には、スタティックプロパティの型付け、型付プロパティのリファレンスについては、実装上の理由により、従来の提案ではサポートされていませんでしたが、本提案ではサポートされるようになり、機能の一貫性に関する改善が図られました。 PHPは弱い型付けのプログラミング言語であり、変数の型は実行時に自動的に選択・変換されます。プログラマが型を陽に指定する必要がないこの特徴は、PHPの使い易さにつながっています。しかしながら、型が自動的に決定されるという仕様は、プログラミングコードの見通しの悪さにつながるため、PHPにおいても変数の型を指定する仕組みが導入されてきました。現在までに、関数およびクラスメソッドの引数については、変数の型指定が可能となっています。しかし、クラスのプロパティの型指定については、サポートされていませんでした。 以下に、クラスFooのプロパティ$aの型に整数型(int)を指定する例を示します。<?php class Foo { public int $a; public ?object $b = null; } $x = new Foo(); $x->a = "123"; var_dump($x->a); // int(123)-3行目でプロパティ$aに対して、intと指定できるようになったのが、新しい機能です。7行目では文字列としてプロパティに”123”を代入していますが、8行目で変数をダンプしてみると、強制的に整数に型変換されて保持されていることがわかります。 4行目に示すようにプロパティ変数のデフォルト値の指定も可能です。なお、オブジェクト型変数$bの型の前の”?”はヌルを代入可能(nullable)であることを示す識別子です。 実行制御変数strict_typesに1を代入することで、プロパティの型指定をより厳密にチェックするモードを指定できます。この場合、プロパティへの代入時に型が宣言時に指定されたものと異なるとエラーを発生します。 下記コードは、上記コードの2行目に”declare(strict_types=1)”を追加・挿入したものです。
<?php declare(strict_types=1); class Foo { public int $a; public ?object $b = null; } $x = new Foo(); $x->a = "123"; var_dump($x->a); // int(123)このスクリプトを実行すると、今度は以下のように型指定に関するエラー(TypeError)を発生して実行が停止します。 Fatal error: Uncaught TypeError: Typed property Foo::$a must be int, string used in test.php:8 8行目で文字列(”123”)を代入している部分は整数値(123)として指定するよう修正する必要があります。 標準では、厳密な型指定(strict_types)は無効となっています。メンテナンス性を向上させるためには、この機能を有効にすることが望ましいと言えます。ただし、既存のコードの動作に影響を与える可能性がありますので、下位互換性を気にする場合は標準モードで使用した上で、厳密な型指定に段階的に移行するようなアプローチも考えられます。