Coding Gun

การใช้งาน 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]);
    }
}

เพราะฉะนั้นในรอบแรกจะเข้า

หลังจากนั้นรอบอื่นๆ ก็จะเป็น

จนรอบสุดท้ายก็จะทำงานแค่ 2 method เท่านั้น

สุดท้ายเราก็สามารถใช้ obj ที่เกิดจาก Customer Class กับ foreach ได้แบบนี้

$customer = new Customer;

foreach($customer as $key => $value) {
    var_dump($key, $value);
    echo "\n";
}
Phanupong Permpimol
Follow me

Software Engineer ที่เชื่อในเรื่องของ Process เพราะเมื่อ Process ดี Product ก็จะดีตาม ปัจจุบันเป็นอาจารย์และที่ปรึกษาด้านการออกแบบและพัฒนา Software และ Web Security