やったこと
シャローコピーとディープコピーの挙動についてPHPで確かめてみた
ClassRoomクラスのmembersプロパティにMemberクラスの配列が入っているような多次元のオブジェクトを以下の3パターンの方法でコピーした結果を比較しました。
・普通に代入
・clone (ClassRoomクラスに__cloneメソッドを定義)
コード
<?php
/**
* Class ClassRoom
*/
class ClassRoom
{
public $id;
public $name;
public $members;
public function __construct(int $id, string $name, array $members)
{
$this->id = $id;
$this->name = $name;
$this->members = $members;
}
public function __clone()
{
// cloneした際に、ClassRoom内のMemberオブジェクトもcloneする
// これが無いと、ClassRoomをcloneしても、members内のオブジェクトはシャローコピーになる
$this->members[0] = clone $this->members[0];
$this->members[1] = clone $this->members[1];
}
}
/**
* Class Member
*/
class Member
{
public $id;
public $name;
public function __construct(int $id, string $name)
{
$this->id = $id;
$this->name = $name;
}
}
// Memberクラスをオブジェクト化
$member = new Member(13, 'Yorinton');
$member2 = new Member(14, 'ピーターパン');
$members = [$member, $member2];
// ClassRoomクラスをオブジェクト化
$classRoomA = new ClassRoom(999, 'A', $members);
// classRoomAをコピー
$classRoomB = $classRoomA;
$classRoomC = clone $classRoomA;
// classRoomAのプロパティを変更
$classRoomA->name = 'B';
$classRoomA->members[0]->name = 'よりとん';
$classRoomA->members[1]->name = 'ポーターピン';
var_dump($classRoomA); // 変更される
var_dump($classRoomB); // 変更される
var_dump($classRoomC); // 変更されない
結果
classRoomA (元のオブジェクト)
object(ClassRoom)#3 (3) {
["id"]=>
int(999)
["name"]=>
string(1) "B"
["members"]=>
array(2) {
[0]=>
object(Member)#1 (2) {
["id"]=>
int(13)
["name"]=>
string(12) "よりとん"
}
[1]=>
object(Member)#2 (2) {
["id"]=>
int(14)
["name"]=>
string(18) "ポーターピン"
}
}
}
classRoomB (普通に代入)
object(ClassRoom)#3 (3) {
["id"]=>
int(999)
["name"]=>
string(1) "B"
["members"]=>
array(2) {
[0]=>
object(Member)#1 (2) {
["id"]=>
int(13)
["name"]=>
string(12) "よりとん"
}
[1]=>
object(Member)#2 (2) {
["id"]=>
int(14)
["name"]=>
string(18) "ポーターピン"
}
}
}
classRoomC (clone※ClassRoomクラスに__cloneメソッドを定義)
・ディープコピーなので元の値から変わってない
object(ClassRoom)#4 (3) {
["id"]=>
int(999)
["name"]=>
string(1) "A"
["members"]=>
array(2) {
[0]=>
object(Member)#5 (2) {
["id"]=>
int(13)
["name"]=>
string(8) "Yorinton"
}
[1]=>
object(Member)#6 (2) {
["id"]=>
int(14)
["name"]=>
string(18) "ピーターパン"
}
}
}
※classRoomC (clone※ClassRoomクラスに__cloneメソッドを定義しない場合)
・membersプロパティにセットしたMemberオブジェクト内のプロパティはシャローコピー
・ClassRoomオブジェクトのnameプロパティはディープコピー
object(ClassRoom)#3 (3) {
["id"]=>
int(999)
["name"]=>
string(1) "A" // ここは変わらない(ディープ)
["members"]=>
array(2) {
[0]=>
object(Member)#1 (2) {
["id"]=>
int(13)
["name"]=>
string(12) "よりとん" // ここは変わる(シャロー)
}
[1]=>
object(Member)#2 (2) {
["id"]=>
int(14)
["name"]=>
string(18) "ポーターピン" // ここは変わる(シャロー)
}
}
}