(CJP) PHP 8.1 では、読み取り専用プロパティを初期化するとすぐにオーバーライドすることはできません。 これは、オブジェクトのクローンを作成し、その読み取り専用プロパティの 1 つを変更することも許可されていないことを意味します。 PHPが何らかの種類を取得する可能性があります clone with 機能は将来的に改善されますが、当面はこの問題を回避する必要があります。
読み取り専用プロパティを持つ単純な DTO クラスを想像してみましょう。
class Post
public function __construct(
public readonly string $title,
public readonly string $author,
)
PHP 8.1 は、投稿オブジェクトを複製して、その読み取り専用プロパティの 1 つをオーバーライドしようとすると、エラーをスローします。
$postA = new Post(title: ‘a’, author: ‘Brent’);
$postB = clone $postA;
$postB->title = ‘b’;
Error: Cannot modify readonly property Post::$title
これが発生する理由は、現在の読み取り専用の実装では、値が初期化されていない場合にのみ値を設定できるためです。 プロパティに既に値が割り当てられているオブジェクトを複製しているため、それをオーバーライドすることはできません。
将来、オブジェクトのクローンを作成し、読み取り専用プロパティをオーバーライドする何らかのメカニズムが PHP に追加される可能性は非常に高いですが、PHP 8.1 の機能凍結が近づいているため、現時点ではこれが含まれないことは確実です。
したがって、少なくとも PHP 8.1 では、この問題を回避する方法が必要になります。 これはまさに私が行ったことであり、なぜあなたも使用できるパッケージを作成したのですか: https://github.com/spatie/php-cloneable.
仕組みは次のとおりです。 最初に composer を使用してパッケージをダウンロードし、次に Spatie\Cloneable\Cloneable クローン可能にしたいすべてのクラスの特性:
use Spatie\Cloneable\Cloneable;
class Post
use Cloneable;
public function __construct(
public readonly string $title,
public readonly string $author
)
今、私たちの Post オブジェクトは with クローンに使用できるメソッド と プロパティを次のようにオーバーライドします。
$postA = new Post(title: ‘a’, author: ‘Brent’);
$postB = $postA->with(title: ‘b’);
$postC = $postA->with(title: ‘c’, author: ‘Freek’);
もちろん、いくつかの注意事項があります。
このパッケージは、オブジェクトのクローンを作成するときにコンストラクターの呼び出しをスキップします。つまり、コンストラクターのロジックは実行されません。 と
の with メソッドは浅い複製になります。つまり、ネストされたオブジェクトも同様に複製されません。
このパッケージは、単純なデータ転送および値オブジェクトに役立つと思います。 これはまさに、読み取り専用プロパティが最初から設計されたオブジェクトのタイプです。
私のユースケースでは、この実装で十分です。 また、私は意見主導の設計を信じているので、それに機能を追加することにも興味がありません。このパッケージは特定の問題を 1 つ解決し、それで十分です。
tpyoに気づきましたか? PR を送信して修正することができます。 このブログの最新情報を知りたい場合は、私をフォローしてください。 ツイッター または私のニュースレターを購読してください: