より使いやすくなったPHP 8.4の新機能──クラス定義や言語仕様とデータベース関連の強化ポイント
ますます便利になるPHPの新機能を探ろう! 第5回
ダウンロード サンプルファイル (3.4 KB)
クラス定義での機能強化
まずは、クラス定義における機能強化について紹介します。
プロパティフック
PHP 8.4では、プロパティフックにより、プロパティに直接ゲッタ/セッタを記述できるようになりました。以前のPHPでは、プロパティのゲッタ/セッタの提供は以下の手段をとっていました。
- getXxxx、setXxxxというメソッドを設ける
- __get、__setといったマジックメソッドを使う
- __constructorメソッド(コンストラクタプロパティプロモーション)で簡略化したゲッタ/セッタを使う(PHP 8.0から)
getXxxx、setXxxxは単なるメソッドであるため、PHPのバージョンを問わず利用できますが、クラス定義がメソッドだらけになり、どのプロパティと対応しているのか分かりにくいといった問題があります。__get、__setではゲッタ/セッタが1箇所にまとまるので一見便利そうに見えますが、メソッド内がswitch文の分岐だらけになったり、漏れが発生したり、構造が複雑になりがちなので静的チェックがやりにくい問題があります。__constructorメソッドによる方法では、そもそもゲッタ/セッタの動作をカスタマイズする余地がありません。
そこでPHP 8.4では、プロパティフックという構文で、プロパティへのアクセスをgetフックとsetフックが横取りするような記述が可能になっています。以下のリストでは、プロパティsoupにsetフックを定義して、適正値のチェックとプロパティへのセットを実行しています。マジックメソッドを使う方法に比較して、プロパティ定義に含めて記述できるので、関連が明確です。
class Ramen
{
public string $soup {
set(string $value) {
if (!in_array($value, array('醤油', '味噌', '塩', '豚骨')))
throw new InvalidArgumentException('サポートしていない味です');
$this->soup = $value;
}
}
public string $noodle {
set(string $value) {
if (!in_array($value, array('太', '細', '縮れ')))
throw new InvalidArgumentException('サポートしていない麺です');
$this->noodle = $value;
}
}
}
$ramen = new Ramen();
$ramen->soup = '塩'; // OK
$ramen->noodle = '細'; // OK
$ramen->soup = '辛味噌'; // 例外
$ramen->noodle = 'バリカタ'; // 例外
仮想プロパティという、値を保持しないプロパティも定義可能です。プロパティの値を加工して返却する場合などに有用です。
public string $soupTaste {
get => $this->soup . '味';
}
public string $noodleType {
get => $this->noodle . '麺';
}
…略…
printf("ご注文は%sで%sです。\n", $ramen->soupTaste, $ramen->noodleType);
// ご注文は塩味で細麺です。
インタフェース内にプロパティフックの存在だけを記述することもできます。
interface Men {
public string $name { get; set; }
}
非対称可視性
PHP 8.4では、ゲッタとセッタに異なる可視性を指定できるようになりました。プロパティの参照時にはpublicでも、設定時にはprivateまたはprotectedになるといった使い分けができます。従来のPHPでは、ゲッタとセッタの可視性は共通でした。
例えば、以下のリストでは、soupプロパティはpublicですが、書き換えのみprivateに指定されているので、外部からの変更はできません。
class Ramen
{
public private(set) string $soup = '塩豚骨'; // 塩豚骨固定
}
$ramen = new Ramen();
$ramen->soup = '塩'; // セッタはprivateなのでエラー
このとき、soupプロパティのpublicは省略できます。コンストラクタプロパティプロモーションによる記述でも、非対称可視性の指定が可能です。
class Udon
{
public function __construct(
public private(set) string $tsuyu,
public private(set) string $men
) {}
}
遅延初期化
PHP 8.4では、インスタンス化をnew時点では実行せず、必要になった時点で実行する遅延初期化がサポートされました。一般的にインスタンス生成は時間のかかる処理となることがあるので、これをできるだけ後回しにしたいという考え方です。専用の実装が必要になるので、ライブラリの開発者などに向けた機能と言えます。
// 時間のかかる処理を含むクラス
class Example {
public function __construct(public int $data) {
printf("時間のかかる処理%d...\n", $data);
}
}
// イニシャライザは初期化を実行する静的関数
$initializer = static function (Example $ghost): void {
$ghost->__construct(12345);
};
// レイジーゴーストオブジェクトを作成する
$reflector = new ReflectionClass(Example::class);
$lazyObject = $reflector->newLazyGhost($initializer);
// ここではインスタンス生成はトリガーされない
var_dump($lazyObject);
// dataプロパティへのアクセスでインスタンス生成がトリガーされる
var_dump($lazyObject->data);
遅延初期化は、対象クラスの他に、インスタンスを実際に生成するイニシャライザ関数と、イニシャライザ関数を受け取って必要になった時点で呼び出すレイジーゴーストにより構成されます。
レイジーゴーストとは、遅延初期化の一つの方法で、対象クラスのオブジェクトに透過的にアクセスできる仕組みを提供し、プロパティへの最初の参照や変更でイニシャライザ関数を呼び出すことで、遅延初期化を達成します。レイジーゴーストは、クラスの情報を取り扱うReflectionClassクラスにPHP 8.4で新設された、newLazyGhostメソッドにイニシャライザ関数を渡すことで生成します。
実行結果は以下のようになります。最初のvar_dumpの実行では、インスタンスは生成されずメッセージは出力されません。次のvar_dumpでdataプロパティへのアクセスが発生するので、ここでイニシャライザが呼ばれ、インスタンスが初期化されることでメッセージが出力されます。
lazy ghost object(Example)#3 (0) { // 最初のvar_dump
["data"]=>
uninitialized(int)
}
時間のかかる処理12345... // 初期化実行
int(12345) // 2番目のvar_dump
この記事は参考になりましたか?
- この記事の著者
-
WINGSプロジェクト 山内 直(WINGSプロジェクト ヤマウチ ナオ)
<WINGSプロジェクトについて>有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。 2026年時点での登録メンバは約50名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きたい。著書、記事多数。 RSS X: @WingsPro_info(公式)、@WingsPro_info/wings(メンバーリスト) Facebook <個人紹介>WINGSプロジェクト所属のテクニカルライター。出版社を経てフリーランスとして独立。ライター、エディター、デベロッパー、講師業に従事。屋号は「たまデジ。」。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
-
山田 祥寛(ヤマダ ヨシヒロ)
静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for Visual Studio and Development Technologies。執筆コミュニティ「WINGSプロジェクト」代表。主な著書に「独習シリーズ(Java・C#・Python・PHP・Ruby・JSP&サーブレットなど)」「速習シリーズ(ASP.NET Core・Vue.js・React・TypeScript・ECMAScript、Laravelなど)」「改訂3版JavaScript本格入門」「これからはじめるLaravel実践入門」「はじめてのAndroidアプリ開発 Kotlin編 」他、著書多数。
※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です
この記事は参考になりましたか?
この記事をシェア
