PHPでオブジェクトのシャローコピーとディープコピーの挙動を確かめた

# やったこと
シャローコピーとディープコピーの挙動についてPHPで確かめてみた

ClassRoomクラスのmembersプロパティにMemberクラスの配列が入っているような多次元のオブジェクトを以下の３パターンの方法でコピーした結果を比較しました。

・普通に代入
・clone (ClassRoomクラスに__cloneメソッドを定義)

# コード

```php
<?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 (元のオブジェクト)

```console
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 (普通に代入)

```console
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メソッドを定義)

・ディープコピーなので元の値から変わってない

```console
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プロパティはディープコピー

```console
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) "ポーターピン" // ここは変わる(シャロー)
    }
  }
}
```