こんにちは!システム開発部の小出です!

12月8日に PHP8.2 がリリースされました!

本日は、PHP8.2 で追加された読み取り専用クラスに関して書いていきます。

それでは早速みていきましょう。

読み取り専用クラス(readonly class)

PHP 8.1 ではプロパティに対して readonly 修飾子を設定することが可能になりましたが、

PHP 8.2 ではクラスに対して readonly 修飾子を設定することが可能になりました。

<?php

readonly class SekarakuBlog
{ 
    public string $title; 
}

上記によって、クラス内の全てのプロパティが readonly になります。

<?php

readonly class SekarakuBlog
{
    public string $title;

    public function __construct()
    {
        $this->title = 'test Title';
    }
}

$test = new SekarakuBlog();
$test->title = 'Change Title'; // Fatal error: Uncaught Error: Cannot modify readonly property SekarakuBlog::$title
$test->content = 'content';    // Fatal error: Uncaught Error: Cannot create dynamic property SekarakuBlog::$content

readonly クラス内のプロパティを書き換えようとすると下記のエラーがでることが確認できます。

Fatal error: Uncaught Error: Cannot modify readonly property SekarakuBlog::$title

さらには、動的プロパティの作成も禁止されます。

動的プロパティを作成しようとすると下記のようなエラーが発生します。

Fatal error: Uncaught Error: Cannot create dynamic property SekarakuBlog::$content

また、PHP 8.2 から動的プロパティが非推奨になりました。

#[AllowDynamicProperties] 属性を記述することで、動的プロパティを引き続き使用することができます。

しかし、readonly クラス内で #[AllowDynamicProperties] を使用することは禁止されており、readonly クラスで #[AllowDynamicProperties] を使用しようとすると、下記のようなエラーが発生します。

<?php
#[AllowDynamicProperties]
readonly class SekarakuBlog {}

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class SekarakuBlog

<?php readonly class SekarakuBlog 
{ 
   public $title; 

   public function __construct() 
   { 
      $this->title = 'test Title'; 
   } 
} 
$test = new SekarakuBlog(); 
// Fatal error: Readonly property SekarakuBlog::$title must have type

プロパティに型を定義していない場合にもエラーが発生するので注意しましょう。

継承

readonly クラスを readonly クラスで継承をすることは可能ですが、

readonly クラスを readonly ではないクラスで継承をしたり、readonly ではないクラスを readonly のクラスで継承をすることは禁止されております。

# 下記は OK
readonly class SekarakuBlog {}
readonly class ExtendSekaraku extends SekarakuBlog {}

# 下記はNG
class SekarakuBlog {}
readonly class ExtendSekaraku extends SekarakuBlog {}
// Fatal error: Readonly class ExtendSekaraku cannot extend non-readonly class SekarakuBlog


readonly class SekarakuBlog {}
class ExtendSekaraku extends SekarakuBlog {}
// Fatal error: Non-readonly class ExtendSekaraku cannot extend readonly class SekarakuBlog

下記メソッドを使用することで、readonly クラスか否かも確認できるようになりました。

readonly class SekarakuBlog
{}

$refrectionClass = new ReflectionClass('SekarakuBlog');
$refrection->isReadOnly(); // true

final クラス修飾子との違い

read only クラスと final クラス修飾子の違いに関しても少し触れます。

read only クラスは上記で説明してきた通り、read only クラス同士の継承は可能でしたが、final クラス修飾子をしたクラスは

クラスの拡張を行うことができません。

ちなみに、クラスの拡張も、値の書き換えも行いたく無い場合は下記の記述をすることができます。


<?php
final readonly class Sekaraku
{
    public string $hoge;

    public function __construct()
    {
        $this->hoge = 'hoge';
    }
}
$test = new Sekaraku();
$test->hoge = 'test';
// Fatal error: Uncaught Error: Cannot modify readonly property Sekaraku::$hoge in /var/www/html/docker/php/finalreadonly.php:17

readonly class Lab extends Sekaraku
{
}
$test2 = new Lab();
// Fatal error: Class Lab cannot extend final class Sekaraku in /var/www/html/docker/php/finalreadonly.php on line 20

メリット

readonly クラスを使用することで、プロパティ毎に readonly 修飾子を設定する必要がなく手間が省けます。

一度設定した値は書き換えることができなくなり、動的プロパティも禁止することができるのでより堅牢なコードを書くことができそうですね。

 

まとめ

今回は PHP8.2 で追加された機能は他にもありましたが全体的に細かい追加機能が多かった印象です。

個人的には動的プロパティが非推奨になった点は今後の PHP ではかなり大きいと思いました。

(クラスのプロパティをクラス外で宣言したときに、どこでそのプロパティが宣言されているか分からなくなりますし

デバッグの効率が落ちると考えているからです。)

使用している方も多いかと思いますので、バージョンを上げる際には注意が必要そうです。

また、紹介できればと思います!

それでは良い PHP ライフを!