LoginSignup
2
3

More than 3 years have passed since last update.

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

Posted at

やったこと

シャローコピーとディープコピーの挙動について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) "ポーターピン" // ここは変わる(シャロー)
    }
  }
}
2
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3