🧈

PHP8.4 readonlyプロパティの動きが少し変わっていた

2024/12/24に公開

この記事は カオナビ Advent Calendar 2024 シリーズ2 20日目の記事です。

はじめに

PHP8.4のリリース後にPHPマニュアルを見ているとreadonlyプロパティの説明に少し追記があった。

PHP 8.4.0 より前のバージョンでは、readonly プロパティは暗黙的に private-set であり、 同じクラス内からのみ書き込みが可能でした。
PHP 8.4.0 以降では、readonly プロパティは暗黙的に protected(set) となり、 子クラスからも設定可能です。必要に応じて明示的に オーバーライドすることもできます。

https://www.php.net/manual/ja/language.oop5.properties.php#language.oop5.properties.readonly-properties

なるほど、どういうことか少し検証してみた。

検証

サンプルコードはこちらです。

<?php

class HelloWorld
{
    readonly public string $say;

    public function __construct() 
    {
        $this->say = 'Hello World';
    }
}

class HelloNewWorld extends HelloWorld
{
    public function __construct() 
    {
        $this->say = 'Hello New World';
    }
}

上記のサンプルコードをためしにこちらで実行してみる。

https://3v4l.org/VKmas

PHP8.2、8.3では実行できないが、PHP8.4では実行できるようになっていますね。(マニュアル通りですね。)

(こんなコードは書かないって人は多いかもしれないが、)
PHP8.3以前では次のように子クラス側でプロパティをオーバーライドすることで値の書き換えを行なっていたが、PHP8.4以降では不要になりそうです。

class HelloNewWorld extends HelloWorld
{
    readonly public string $say;

    public function __construct() 
    {
        $this->say = 'Hello New World';
    }
}

再度ためしに実行してみると,,,

https://3v4l.org/TQQ08

PHP8.2、8.3、8.4で動いていますね。

ただし、コンストラクタのプロモーションを使っている場合はあまり意識する必要はないかもしれないです。

class HelloNewWorld extends HelloWorld
{
    public function __construct(readonly public string $say = 'Hello New World') 
    {
    }
}

https://3v4l.org/Avre7

こちらでもPHP8.2、8.3、8.4で動いていますね。

まとめ

PHP8.4ではプロパティフック、非対称可視性プロパティといった新機能が注目されますが、
既存の機能に対しても色々と変更が入っていることも多いので、マニュアルはしっかり見ましょうね。

今回の発見ではあまり感じないけど、
別の何かの変更からコードが思わぬ動きをして、デバッグ地獄に陥るかもしれませんよ!っていうお話です。

GitHubで編集を提案

Discussion