การใช้งาน Countable และ Iterator
ก่อนจะไปดูวิธีการใช้งาน Countable และ Iterator ใน PHP เราต้องทบทวนเรื่อง interface กันก่อน เพราะ Countable และ Iterator คือ Interface ที่เราต้องนำมา Implement ให้กับ Class ที่เราต้องการให้สามารถนับได้(ใช้ function count นับจำนวนสมาชิกได้: Countable)และสามารถวนloop ด้วย foreach ได้(Iterable)
การเขียน PHP แบบ Object-Oriented หรือ OOP เราจำเป็นต้องรู้จักการใช้งาน interface เพราะจุดประสงค์ของ interface คือการเป็นจุดเชื่อมต่อของ code 2 ส่วนถ้าเราไม่มี interface เข้ามาคั่นกลางเราจะไม่สามารถแยก 2 ส่วนนี้ออกจากกันได้ เช่นการที่เราใช้ interface iterator จะเป็นจุดเชื่อมต่อของ code 2 ส่วนคือคำสั่ง foreach(ซึ่งเป็นของ PHP เอง) และ object ของเรา ดังนั้นจะเห็นว่าถ้าเราอยากได้ object ตัวไหนทำงานกับ foreach ได้ เราก็แค่ implement interface ที่ชื่อว่า iterator แค่นี้เอง แล้ว iterator จะบอกเราเองว่า เราต้อง implement method หรือ function อะไรบ้าง (เราสามารถเอา object ของเราไปทำงานกับ foreach ได้โดยที่ไม่ต้องเข้าไปแก้ไข code ของ PHP นี่คือประโยชน์ของ interface)
การใข้งาน Interface Countable
ในการทำงานกับ object ใดๆ ในบางครั้งเราอยากจะให้ object ของเรามี function count เหมือนกับ array บ้าง เพราะบางทีเราอยากได้จำนวนของ object นั้นๆไปประยุกต์ใช้งานทำอย่างอื่น แต่เราไม่สามารถที่จะใช้ function count ได้เหมือนกับ array
// Code จะ Error เพราะไม่สามารถใช้ function count กับ object ได้
count($object)
วิธีการที่จะทำให้ object นั้นสามารถ count ได้ ก่อนอื่นเราต้องทำการ count มันให้ได้ก่อน ขึ้นอยู่กับว่าเราเลือกที่จะ count ด้วยวิธีไหน อาจเป็นการ count โดย Query ข้อมูลจากฐานข้อมูล โดยใช้ SELECT COUNT(*) …. หรือการ count object โดยการนับ object ที่ทำการ new ขึ้นมาก็แล้วแต่ เราจะไม่ได้ลงในรายละเอียดของวิธีการ count แต่ละแบบ แต่ในตัวอย่างเราจะเลือกอย่างหลังคือทำการนับ object ที่ได้ทำการ instantiate ขึ้นมา
class Student{
private static $num = 0;
function __construct(){
self::$num++;
}
}
ในตัวอย่างนี้ตัวแปร $num จะเพิ่มขึ้นทุกครั้งที่มีการ new Student ขึ้นมาใช้งาน แต่จุดประสงค์หลักของบทความนี้คือต้องการเอาค่า $num ที่นับได้ไปแสดงผลโดยการใช้ function count เราเลยต้องทำการ implement interface ที่ชื่อว่า countable เพื่อให้ใช้ function count กับ object นี้ได้
class Student implements Countable{
private static $num = 0;
function __construct(){
self::$num++;
}
function count(){
return self::$num;
}
}
เพียงแค่นี้เราก็จะสามารถใช้ function count กับ object ได้แล้ว
การใช้งาน Iterface Iterator
ทำไมต้องมี interface iterator ก็เหมือนกับหัวข้อ countable ก่อนหน้านี้ที่เราต้องการให้ object ที่เราสร้างขึ้นสามารถใช้งานฟังก์ชั่น count ได้เหมือนกับ array เราจะใช้ interface ที่ชื่อว่า countable ในตอนนี้เราก็เลยอยากจะให้ object ที่เราสร้างขึ้นสามารถใช้งาน foreach loop ดูบ้าง
มาลองใช้งาน interface iterator กันโดยเริ่มจาก
class Customer implements Iterator {
.....
}
ต่อจากนั้นให้ implement method 5 method นี้
class Customer implements Iterator {
// ส่วนนี้จะเป็นส่วนของการกำหนดค่าเริ่มต้น เพื่อใช้เป็นตัวอย่าง ในชีวิตจริงอาจเป็นข้อมูลที่ได้มาจาก Database หรือแหล่งอื่นๆ
// และเราอาจใช้ Data structure อื่นๆอย่าง Dictionary แทน Array ก็ได้
private $position = 0;
private $array = array(
"John",
"Jenny",
"Martin",
);
// Method ที่จำเป็นต้องมีเนื่องจาก Implement Iterator
// ทำงานครั้งแรกก่อนจะเข้า loop ครั้งเดียว เป็นการกำหนดค่าเริ่มต้น
function rewind() {
$this->position = 0;
}
// ทำงานตอนที่จะดึงค่า value ทุกรอบ
function current() {
return $this->array[$this->position];
}
// ทำงานตอนที่จะดึงค่า key ทุกรอบ
function key() {
return $this->position;
}
// หลังจากที่เราดึง value ออกมาแล้วจะเข้า method นี้เพื่อเลื่อนไปยัง สมาชิกตัวถัดไป
function next() {
++$this->position;
}
// ทำงานหลังจาก next เพื่อทำการตรวจสอบว่ายังมีสมาชิกอยู่อีกหรือไม่
function valid() {
return isset($this->array[$this->position]);
}
}
เพราะฉะนั้นในรอบแรกจะเข้า
- rewind
- valid
- current (ถ้ามีข้อมูล)
- key(ถ้ามีข้อมูล)
หลังจากนั้นรอบอื่นๆ ก็จะเป็น
- next
- valid
- current
- key
จนรอบสุดท้ายก็จะทำงานแค่ 2 method เท่านั้น
- next
- valid
สุดท้ายเราก็สามารถใช้ obj ที่เกิดจาก Customer Class กับ foreach ได้แบบนี้
$customer = new Customer;
foreach($customer as $key => $value) {
var_dump($key, $value);
echo "\n";
}