วันอาทิตย์ที่ 26 พฤษภาคม พ.ศ. 2556

PHP clone มาเรียนรู้การ clone object กันครับ

เกริ่นก่อน การ copy object ของ php จริงๆ หลายคนอาจจะนึกถึงอะไรน้อ

$a = $b; หรือว่า clone นั่นแหลครับที่จะมาพูดกัน มาดูแบบแรกกันเลย

1. ใส่เท่ากับกันตรง ๆ (direct equal)
class CopyMe {}
$first = new CopyMe();
$second = $first;
// PHP 4: $second กับ $first จะเป็น 2 object ที่อ้างอิง address คนละอันกันครับซึ่งคือคือคนละ object นั่นเอง
// PHP 5 : $second กับ $first จะถูกมองเป็น object เดียวกันครับ

ซึ่งวิธีนี้อาจจะทำให้เกิดความสับสนกันได้ มาดูวิธีที่ตั้งใจจะมาบอกกันดีกว่าครับ

2. ใช้ฟังก์ชั่น clone (clone function)
วันนี้จะมาเล่นกับ clone นั่นเอง ใครเคยใช้แล้วยกมือขึ้น โย่ว

class CopyMe {}
$first = new CopyMe();
$second = clone $first;

ในเคสนี้ จะได้  $second กับ $first จะเป็นคนละ object กันครับ ฟังก์ชั่น clone จะเป็นการ copy value จาก object นึงไปอีก object นึงครับ ซึ่ง address จะไม่ถูกนำมาด้วย

------------------------------------------------------------------------------------

เทคนิคต่อไป หากเรามีค่าที่ไม่อยากให้ติดมาด้วยหละ เช่น entity ของ database ที่มี $id ที่ไม่อยากให้นำค่ามาด้วย จะทำยังไงดีน้อ เรามีข้อเสนอคือการ overide หรือการเขียนทับ __clone() นั่นเอง มาดูกันเลย

class Person {
  private $name;
  private $age;
  private $id;

  function __construct( $name, $age ) {
    $this->name = $name;
    $this->age = $age;
  }

  function setId( $id ) {
    $this->id = $id;
  }

  function __clone() {
    $this->id = 0;  // ทำการกำหนดค่า id ให้เป็น 0 เมื่อเกิดการ clone ครับ
  }
}

$person = new Person( "me", 27 );
$person->setId( 343 );
$person2 = clone $person;
// $person2 :
// name: me
// age: 27
// id: 0

ง่ายมั้ยครับ 

------------------------------------------------------------------------------------

เอา next step ต่อไปมาดูว่าถ้าใน object ของเรา reference ของ object อื่นด้วยหละ

class Account {
  public $balance;
  function __construct( $balance ) {
    $this->balance = $balance;
  }
}

class Person {
  private $name;
  private $age;
  private $id;
  public $account;   // ตัวนี้เป็น Object ของ Account ครับ ซึ่งเมื่อถูก clone จะได้ reference ไป
  function __construct( $name, $age, Account $account ) {
    $this->name = $name;
    $this->age = $age;
    $this->account = $account;
   }

   function setId( $id ) {
     $this->id = $id;
  }

  function __clone() {
    $this->id = 0;
  }
}
$person = new Person( "bob", 44, new Account( 200 ) );
$person->setId( 343 );



//เรามาเพิ่มเงินให้หน่อยดีกว่า คราวนี้คนแรกมีเงิน 210 บาทแล้ว
$person->account->balance += 10;

//เอ๊ะ ทำไมคนที่สองก็มีเงิน 210 บาทเหมือนกันเพราะเป็นการ copy reference มานั่นเอง
print $person2->account->balance;

------------------------------------------------------------------------------------

แก้โดย
function __clone() {
  $this->id = 0;
  $this->account = clone $this->account;
}

ใส่ clone ซ้ำใน __clone() ซะเลย แค่นี้ก็เรียบร้อยแล้ว

หวังว่าจะทำให้เกิดไอเดียใช้สนุก ๆ นะครับ

ความรู้จาก PHP Obejcts, Pattern and Practice (3rd)