毎日のメモ: PHP プロトタイプ パターン
プロトタイプ パターンとは、既存のインスタンスをコピーして新しいインスタンスを取得することを指します。
プログラム設計では、オブジェクトをインスタンス化するために大量の初期化作業を行う必要がある場合があり、非常に時間がかかる場合は、プロトタイプ モードを使用して新しいインスタンスを取得することを検討できます。
実際、PHP では、clone キーワードを使用してオブジェクトを簡単にコピーできます。さらに、マジック メソッド __clone() を使用して、クローン作成時に実行する必要がある操作を指定します。これは実際にはプロトタイプ モードの実装です。もちろん、コードをよりエレガントで完全に見せるための場合もあります。関連する実装を自分で書くこともできますが、もちろん clone キーワードも使用する必要があります。
<?php interface Cloneable{ public function copy(); } class Task implements Cloneable{ public $name; public $startTime; public function __construct($name){ //这里实例化Task需要做很多工作 $this->name = $name; $this->startTime = time(); } public function copy(){ return clone $this; } }
$task1 = 新しいタスク("タスク1");
Task インスタンスができたので、新しいタスク インスタンスを取得したい場合は、clone メソッドを使用できます
$task2 = $task1->copy();
しかし、ここでは $task1 と $task2 の startTime を出力します。それらは同じであり、クローンされたオブジェクトの時刻が現在の時刻であることを望みます。したがって、オブジェクトの複製が試行されるときに自動的に呼び出される __clone メソッドを作成する必要があります。改良したコードは以下の通りです
class Task implements Cloneable{ public $name; public $startTime; public function __construct($name){ //这里实例化Task需要做很多工作 $this->name = $name; $this->startTime = time(); } public function __clone(){ //在克隆的时候把startTime设为当前时间 $this->startTime = time(); //克隆的时候需要执行的操作 } public function copy(){ return clone $this; } }
もちろん、これは単なるプロトタイプ モードです。実際のクローン作成では、浅いクローン作成と深いクローン作成に分かれます。
浅い複製: つまり、オブジェクトが clone メソッドを呼び出すと、基本データ型のみが複製され、オブジェクトに他のオブジェクトへの参照が含まれている場合は、他のオブジェクトの参照がコピーされます
ディープ クローン作成: 基本データ型のクローン作成に加えて、参照型のデータもクローン化されます。
たとえば、私のタスク クラスには、Parent などの他のオブジェクトへの参照が含まれています。関連するコードは次のとおりです:
class TaskParent{ public $name; public function __construct($name){ $this->name = $name; } } class Task implements Cloneable{ public $name; public $startTime; public $parent; public function __construct($name){ //这里实例化Task需要做很多工作 $this->name = $name; $this->startTime = time(); //这里直接new一个parent $this->parent = new TaskParent("do some work"); } public function __clone(){ //在克隆的时候把startTime设为当前时间 $this->startTime = time(); //克隆的时候需要执行的操作 } public function copy(){ return clone $this; } }
$task1 = new Task("Task1"); echo $task1->parent->name."\r\n"; //clone一个对象 $task2 = $task1->copy(); echo $task2->parent->name."\r\n"; //将task1的parent的name设为另外的值 $task1->parent->name = "do another work"; //打印task2的parent的值 echo $task2->parent->name;上記のコードの最後の文は do another work を出力します。これは、task1 の親を変更すると task2 に影響することを意味します。これは典型的な浅いクローンです。深いクローンを実現したい場合は、次の変更を加えることができます
class Task implements Cloneable{ public $name; public $startTime; public $parent; public function __construct($name){ //这里实例化Task需要做很多工作 $this->name = $name; $this->startTime = time(); //这里直接new一个parent $this->parent = new TaskParent("do some work"); } public function __clone(){ //在克隆的时候把startTime设为当前时间 $this->startTime = time(); //克隆parent $this->parent = clone $this->parent; //克隆的时候需要执行的操作 } public function copy(){ return clone $this; } }
実際のコーディング環境では、1 つのオブジェクトが他のオブジェクトへの参照を多数保持し、他のオブジェクトが多数の参照を保持する場合があります。参照は不確実であるため、最初にディープ クローン作成が必要なオブジェクトとそうでないオブジェクトに注意を払う必要があります。
高速なディープ クローン作成を実現したい場合は、インターネット上の友人が次のコードを使用した簡単な方法を提供してくれました。
class Task implements Cloneable{ public $name; public $startTime; public $parent; public function __construct($name){ //这里实例化Task需要做很多工作 $this->name = $name; $this->startTime = time(); //这里直接new一个parent $this->parent = new TaskParent("do some work"); } public function __clone(){ //在克隆的时候把startTime设为当前时间 $this->startTime = time(); //克隆parent $this->parent = clone $this->parent; //克隆的时候需要执行的操作 } public function copy(){ //return clone $this; //这里不使用clone关键字,而是使用序列化和反序列化来进行 return unserialize(serialize($this)); } }