Menu
Coddy logo textTech

__clone とオブジェクトの複製

CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 48/91。

PHPであるオブジェクトを別の変数に代入しても、コピーは作成されません。両方の変数は同じオブジェクトを指します。実際に独立したコピーを作成するには、cloneキーワードを使用する必要があります。

<?php
class Product {
    public function __construct(
        public string $name,
        public float $price
    ) {}
}

$original = new Product("Laptop", 999.99);
$copy = clone $original;

$copy->price = 899.99;
echo $original->price . " - " . $copy->price;

出力:

999.99 - 899.99

デフォルトでは、PHPは浅いコピーを実行します。つまり、すべてのプロパティ値を直接コピーします。これはスカラー値では問題なく機能しますが、オブジェクト内のオブジェクトは同じインスタンスを参照し続けます。__clone() magic methodを使うと、この動作をカスタマイズできます。

<?php
class Order {
    public function __construct(
        public int $id,
        public array $items = []
    ) {}
    
    public function __clone(): void {
        $this->id = 0;
        $this->items = [];
    }
}

$order1 = new Order(101, ["Book", "Pen"]);
$order2 = clone $order1;

echo "Original: " . $order1->id . ", Clone: " . $order2->id;

出力:

Original: 101, Clone: 0

浅いコピーが作成された後、新しいオブジェクトに対して__clone() methodが呼び出されます。ここでIDをリセットしたり、ネストされたオブジェクトの新しいコピーを作成したり、cloneが完全に独立するために必要なクリーンアップを実行したりします。

challenge icon

チャレンジ

簡単

cloning によって独立したコピーが作成される仕組みと、__clone() magic method によってオブジェクトが cloned されたときの動作をカスタマイズする方法を示す document versioning system を構築しましょう。

コードを 2 つのファイルに分けて整理します。

  • Document.php: versioned document を表す Document class を Create します。constructor promotion を使用して、public $title(string)、public $content(整数)、public $version(整数、default は 1)を定義します。current timestamp を保存する private $createdAt property を追加します(constructor では date('Y-m-d H:i:s') を使用します)。 document には次のものが必要です。
    • getCreatedAt(): creation timestamp を返します
    • __clone(): document が cloned されたとき、version を 1 増やし、$createdAt を current timestamp に Reset します(clone は "now" に created された新しい version です)
  • main.php: Document file を Include します。3 つの inputs(title、content、cloned version 用の new content string)を受け取ります。title と content を使って Document を Create します。次にそれを clone して新しい version を作成し、clone の content を new content string に Update します。 4 行を Print します。
    • original document の version
    • cloned document の version
    • original document の content
    • cloned document の content

この system は、__clone() によって cloning 中の動作を制御できることを示します。original document は自身の version と creation time を保持し、clone は fresh timestamp を持つ新しい version に自動的になります。各 clone が新しい revision を表すため、document history の追跡に最適です。

自分で試してみよう

<?php

require_once 'Document.php';

// 入力を読み取る
$title = trim(fgets(STDIN));
$content = trim(fgets(STDIN));
$newContent = trim(fgets(STDIN));

// TODO: タイトルとコンテンツで Document を作成する

// TODO: ドキュメントをクローンして新しいバージョンを作成する

// TODO: クローンのコンテンツを新しいコンテンツ文字列に更新する

// TODO: 4行を出力する:
// 1. 元のドキュメントのバージョン
// 2. クローンされたドキュメントのバージョン
// 3. 元のドキュメントのコンテンツ
// 4. クローンされたドキュメントのコンテンツ

?>
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: PHPオンラインコンパイラ