lt1

PHP 8.3 での読み取り専用プロパティの複製

PHP 8.3 では、オブジェクトのクローン作成中に読み取り専用プロパティ値を上書きできる機能が追加されました。 ただし、誤解しないでください。オブジェクトのクローンを作成したり、その読み取り専用の値をどこからでも上書きしたりすることはできません。 この機能は、非常に特殊な (ただし重要な) エッジケースのみに対応します。

見てみましょう!

理想的な世界では、ユーザー定義の値のセットに基づいて、読み取り専用プロパティを持つクラスのクローンを作成できるでしょう。 いわゆる clone with 構文 (存在しません):

readonly class Post
{
    public function __construct(
        public string $title,
        public string $author,
        public DateTime $createdAt,
    ) {}
}

$post = new Post(
    title: 'Hello World',
    
);

 
$updatedPost = clone $post with {
    title: 'Another One!',
};

現在の RFC のタイトルを読むと、「読み取り専用プロパティはクローン作成中に再初期化できる」というようになります。次のようなことを考えるかもしれません。 clone with これが可能になりました。 しかし…そうではありません。 RFC では、マジックで読み取り専用の値を上書きするという 1 つの特定の操作のみが許可されています。 __clone 方法:

readonly class Post
{
    public function __construct(
        public string $title,
        public string $author,
        public DateTime $createdAt,
    ) {}
    
    public function __clone()
    {
        $this->createdAt = new DateTime(); 
        
        
    }
}

これは役に立ちますか? そうです! ネストされたオブジェクトを使用してオブジェクトのクローンを作成したいとします。別名「ディープ クローン」を作成します。 この RFC では、それらのネストされたオブジェクトのクローンを作成し、それらが読み取り専用プロパティである場合でも、新しく作成したクローンで上書きすることができます。

readonly class Post
{
    public function __clone()
    {
        $this->createdAt = clone $this->createdAt; 
        
        
    }
}

この RFC がなければ、クローンを作成できます。 $post、ただし、オリジナルへの参照は保持されます。 $createdAt 物体。 そのオブジェクトに変更を加えるとします (これは可能です。 readonly 割り当てられたプロパティの変更を防ぐだけであり、内部値の変更は防ぎません):

$post = new Post();

$otherPost = clone $post;

$post->createdAt->add(new DateInterval('P1D'));

$otherPost->createdAt === $post->createdAt; 

そうすれば、最終的には $createdAt 両方のオブジェクトの日付が変更されました。

この RFC のおかげで、これらのプロパティが読み取り専用の場合でも、すべてのネストされたプロパティも複製された実際のクローンを作成できます。

$post = new Post();

$otherPost = clone $post;

$post->createdAt->add(new DateInterval('P1D'));

$otherPost->createdAt === $post->createdAt; 

#個人的なメモとして

PHP 8.3 で読み取り専用プロパティのディープ クローン作成が可能になったのは良いことだと思います。 しかし、私は 持っている この実装については複雑な気持ちです。 ちょっと想像してみてください clone with PHP に存在する場合、上記のすべては不要です。 ご覧ください:


$updatedPost = clone $post with { 
    createdAt: clone $post->createdAt,
};

さあ、想像してみてください clone with PHP 8.4 で追加される — もちろん、純粋な憶測です。 これは、PHP で同じことを行うには 2 つの方法があることを意味します。 あなたはどうか知りませんが、私は言語やフレームワークが同じことを行う複数の方法を提供するのが好きではありません。 私の知る限り、これはせいぜい次善の言語設計です。

もちろんこれは次のことを前提としています clone with マッピング ロジックを手動で実装する必要がなく、値をプロパティに自動的にマッピングできます。 __clone。 私もそれを想定しています clone with プロパティの可視性を扱うことができます。外部からはパブリック プロパティのみを変更できますが、クラス内で使用される場合は保護されたプロパティとプライベート プロパティを変更できます。

少し前に、PHP の内部がどのように分裂しているようで、あるグループが 1 つの解決策を考え出す一方で、別のグループが別のアプローチをとろうとしていることについて書きました。 私にとって、これは委員会による設計の明らかな欠点です。

完全な開示 – RFC に記載 clone with 将来の範囲として:

将来に向けて想定されているアイデアはいずれも、この RFC の提案と衝突しません。 したがって、それらは後で個別に検討することができます。

しかし、少なくとも次のように仮定すると、私はこの意見に反対する傾向があります。 clone with ユーザーランドコードを実装しなくても機能します。 この現在の RFC の傾向に従えば、誰かが次のように追加することを提案するのが想像できます。 clone with データを渡す方法としてのみ __cloneそしてユーザー自身に対処してもらいます。

readonly class Post
{
    public function __clone(...$properties)
    {
        foreach ($properties as $name => $value) {
            $this->$name = $value;
        }
    }
}

しかし、そうでないことを心から願っています clone with 実装される。 を追加する必要があるため、 __clone すべての読み取り専用クラスに実装します。

したがって、最良のケースを想定すると、 clone with 追加され、値を自動的にマッピングできる場所。 その場合、この現在の RFC の機能は無効になり、同じことを行う 2 つの方法ができるようになります。 コーディング時にさらに別の決定を迫られるため、ユーザーは混乱するでしょう。 PHP はこのままでも十分にわかりにくくなっていると思うので、その変化を見てみたいと思っています。

一方で、私はこの RFC 自体に反対しているわけではないことにも言及しておきたいと思います。 ニコラとマテは、現実の問題に対してしっかりとした解決策を考え出すという素晴らしい仕事をしたと思います。


PS: 実装するだけで済むため、誰かが現在の RFC について議論したい場合に備えて __clone オブジェクトごとに 1 回だけ実行すれば、呼び出しサイトではもう心配する必要はありません。 これらの例単独では、非常に重要な詳細が 1 つ欠けています。それは、単純なサンプルではディープ コピーは発生しないということです。 clone 電話。 ほとんどの場合、ディープコピーのようなパッケージが使用されるため、潜在的なオーバーヘッドが発生します。 clone with example はこれらのパッケージによってすでに処理されているため、エンドユーザーを煩わせることはありません。

次の投稿
私は軽い計画家です -stitcher.io
前の投稿
タスク スケジューラ タスクでエラーが発生しました (修正)

ノート:

AZ: 動物の世界、ペット、ペット、野生の自然に関するカテゴリー記事…
SP:スポーツカテゴリー。
New vs Ne: ニュースコラム。
Te: テクノロジー カテゴリ。
Gt:エンターテインメントカテゴリー。
Bt: 占い、星占い、超常現象、超常現象。
Ta:人生コラム。