7月も終わりとなり,暑い日が続いています。引き続きPHPの次のマイナーバージョンであるPHP 8.5の開発が、8月のフィーチャーフリーズに向けて順調に進んでいます。本連載では、前回に引き続きPHP 8.5で強化される機能について紹介していきます。
PHPのセキュリティ監査が実施される
PHPは、Webアプリケーション向けのスクリプト言語として、世界中の多くのユーザに利用されています。PHPにセキュリティ上の脆弱性が存在した場合には、サーバの乗っ取り、パスワードの漏洩など、重大な影響を与える可能性があります。
オープンソースであるPHPのソースコードは変更点を中心に常時レビューされていますが、セキュリティ上の脆弱性は開発者自身にも発見が難しいものが存在します。 PHPのソースコードの詳細なセキュリティ監査を昨年実施した際のレポートがPHPファウンデーションから4月10日に発行されました。
PHPファウンデーションは、HPの開発者を支援する非営利団体です。本セキュリティ監査は、PHPファウンデーションとOSTIFが企画,Quarkslab社が実施しました。予算の関係で、PHPのコード全体ではなく、最も重要な部分を対象として監査が行われました。
この結果、4件のセキュリティ脆弱性(CVEを発行するレベル)を含む17件のセキュリティ関連の問題が指摘されました。深刻度が高いものが3件、中程度が5件、低いものが9件となっており、すでに昨年(2024年)11月に修正済みとなっています。この中には、MySQLサーバ情報の漏洩に関する脆弱性(CVE-2024-8929)が含まれます。
なお、昨年11月、PHP 8.4系の最初のリリース(PHP 8.4.0)が直前にキャンセルされ、PHP 8.4.1としてリリースされたことがありました。このキャンセルは、リリース直前にこのセキュリティ関連の修正が適用された際、混乱を避けるために、リリースを回避したとのことです。このように、ゼロデイ攻撃を避けるため、セキュリティ脆弱性に関する情報は、修正パッチの適用までは一部の開発者のみに情報が限定されることがあります。
今後、このようなセキュリティ監査が定期的に行われるかについては不明ですが、PHPファウンデーションが2021年11月に設立されて以降、非営利団体として個人や企業の寄付により運営され、PHP自体の品質向上に貢献してきた成果の一つと言えるでしょう。
クローン時のプロパティ設定
続いて、PHP 8.5で導入される予定の新機能について紹介します。PHPでは、cloneにより、オブジェクトのコピーを作成することができます。’=’による通常の代入では、オブジェクトの実体が共有されるシャローコピーとなりますが、cloneによるコピーの場合は、実体が共有されず新規に同一の値を有するオブジェクトが作成されるいわゆるディープコピーとなります。
この際、readonlyのプロパティを変更したい場合があります。readonlyが付与されたプロパティは、オブジェクトの生成時にコンストラクタ内で値を設定することが可能ですが、従来、クローンによるオブジェクトのコピーを行う際には変更・設定を行うことができませんでした。
PHP 8.5では、cloneにオプション引数を指定する機能を付与することで、readonlyが付与されたプロパティであっても変更ができるようになります。
具体的な例をみてみましょう。
<?php
class Foo {
public function __construct(
private readonly int $c = 1,
) {}
public function just_clone() {
return clone $this;
}
public function clone_with($newC) {
return clone($this, [“c” => $newC]);
}
}
$x = new Foo();
クラスFooを定義し、インスタンス$xを生成しています。以下のようにクラスFooのメソッドjust_clone(),clone_with() をコールすると,それぞれ、従来のクローン、引数を指定したクローンが行われます。
var_dump($x->just_clone()); // { [“c”:”Foo”:private]=> int(1) }
var_dump($x->clone_with(5)); // { [“c”:”Foo”:private]=> int(5) }
clone_withには、引数として整数値が指定されており、readonlyのプロパティ変数$cの値が初期値の1から指定した値(5)に変更されていることがわかります。cloneは従来「clone オブジェクト」のように指定しますが、引数を指定する場合は「clone(オブジェクト, [”変数名”=>値])」 のように関数形式で指定します。
プロパティプロモーション でfinalが利用可能に
PHP 8では、コンストラクタの引数でプロパティの作成および値の指定が可能な「コンストラクタ・プロパティ・プロモーション」という便利な機能がサポートされています。この機能は、PHP 8.0で導入されましたが、PHP 8.1 においてreadonlyが指定されたプロパティにも適用できるように機能が拡張されています。さらにPHP 8.5では、finalが指定されたプロパティにも適用できるよう機能が拡張されます。
ここで、以下のようにクラスBがクラスAの定義を継承する例を見てみましょう。
class A {
public function __construct(
public final $prop { get {} set {} }
) {}
}
class B extends A {
public $prop { get {} set {} }
}
readonlyは初期化後の値の変更を禁止しますが、finalは継承時の定義変更を禁止します。この例では、クラスAのコンストラクタの引数において、finalを指定したpublicプロパティ $prop にはプロパティアクセスフック(getおよびset)が指定されています。一方、継承後のクラスBにおいては、finalを除き、定義が変更されておらず、定義が同一となっています。この場合は、エラーを発生することなく、実行されます。
次に、以下の例をみてみましょう。この例では、クラスAコンストラクタの引数において、プロパティ$propが指定されていますが、プロパティのアクセスフックは指定されていません。一方、継承先のクラスBにおいては、前の例と同様にプロパティのアクセスフック(getおよびset)が指定されています。この場合、finalが指定されたプロパティに関して、継承先のクラスにおいて定義が変更されていますので、エラーを発生します。
class A {
public function __construct(
public final $prop
) {}
}class B extends A {
public $prop { get {} set {} }
}
コンストラクタ・プロパティ・プロモーションは、プロパティの作成・初期化を簡易的に行う仕組みとして、非常に便利であり、PHP 8.5においてfinalも指定可能となったことで、より広く利用されると期待されます。
今回は、PHPに関するセキュリティ監査の話題、次期マイナーバージョンであるPHP 8.5に関する情報として変更点および追加される機能のいくつかを紹介しました。今回紹介した機能以外にも新たな機能の導入や変更が予定されており、次回以降で紹介する予定です。