Belajar Iterator Pattern dalam PHP - Design Pattern

Ahmad Oriza 9 Maret 2020

Belajar Iterator Pattern dalam PHP - Design Pattern

Pengertian Iterator

Iterator adalah salah satu bahasan yang menarik dalam dunia design pattern. Kalau kita terjemahkan ke bahasa Indonesia Iterator/Iteration adalah Iterasi atau pengulangan. Tapi nyatanya lebih dari sekedar mengurusi pengulangan. Iterator kurang lebih adalah sebuah konsep bagaimana cara kita mengolah suatu collection dengan teknik yang umumnya dipakai banyak programmer. Pattern iterator juga berguna sebagai abstraksi dari real data yang kita olah. Kita memanfaatkan teknik Iterator untuk mengolah berbagai data seperti XML, JSON, Array, dsb dengan sebuah interface baku.

Nah, selanjutnya apa sih collection? Collection tidak lebih adalah suatu data. Data siswa, data koordinat, data guru, data artikel, data transaksi dan sebagainya.

Dalam pemrograman sering sekali kita mengurusi suatu data. Bahkan sepertinya suatu aplikasi yang kita bikin tidak akan lepas dari yang namanya data. Dimulai dari development IoT sampai Web Development pasti isinya sedikit atau banyak adalah mengatur, mengakses, meyimpan, dan memanipulasi data. Dalam praktiknya data tersebut bisa saja kita looping, kita akses/traverse, kita ubah, dsb.

Untuk memahami Iterator Pattern sebaiknya teman-teman sudah ada pengetahuan dasar tentang OOP dan pernah membuat suatu aplikasi dengan PHP. Disini saya akan coba beri contoh kode seperti berikut :

<?php // Sebuah koleksi data artikel. $articles = [ 0 => [ 'title' => 'Judul 1', 'content' => 'Konten 1' ], 1 => [ 'title' => 'Judul 2', 'content' => 'Konten 2' ], 2 => [ 'title' => 'Judul 3', 'content' => 'Konten 3' ] ]; print_r($articles); ?>

Kode diatas adalah contoh sebuah koleksi data bertipe array. Yang misalnya bisa datang dari Database, API, dan sebagainya. Kita langsung tulis saja untuk memperpendek kode.

Output kode diatas adalah :

Array ( [0] => Array ( [title] => Judul 1 [content] => Konten 1 ) [1] => Array ( [title] => Judul 2 [content] => Konten 2 ) [2] => Array ( [title] => Judul 3 [content] => Konten 3 ) )

Sekilas memang tidak ada masalah dengan kode diatas. Dia hanya sebuah array yang kita tampilkan outputnya. Biasanya data array tersebut kita passing ke sebuah template bukan? misal ke sebuah view jika menganut MVC. Bisa jadi juga data tersebut diolah dulu seperti filtrasi, validasi dan sebagainya.

Nah untuk kasus sekarang, bagaimana jika sebelum kita passing ke view/template, kita ingin filtrasi, jika judul bernama "Judul 2" maka hapus datanya, hapus indexnya sehingga tidak tampil. Nah kita dapat melakukannya dengan bantuan Iterator dari PHP. Contohnya seperti berikut ini :

<?php // Sebuah koleksi data artikel. $articles = [ 0 => [ 'title' => 'Judul 1', 'content' => 'Konten 1' ], 1 => [ 'title' => 'Judul 2', 'content' => 'Konten 2' ], 2 => [ 'title' => 'Judul 3', 'content' => 'Konten 3' ] ]; // Mengkonversi data array menjadi object. $articles = new ArrayObject( $articles ); // Mengimplementasikan Iterator pada array tersebut dengan method getIterator. $object = $articles->getIterator(); // Maka sampai disini array kita sudah berubah menjadi object yang support iterator. // Sekarang kita coba looping ya dengan iterator method. while( $object->valid() ) { if ($object->current()['title'] == 'Judul 2') // Kalau ketemu Judul 2 unset($articles[$object->key()]); // Hapus. $object->next(); } // Kasih batas echo "\n"; // Cetak ulang articles print_r($articles); ?>

Sekarang Judul 2 sudah tidak tampil, dan array kita sudah berubah menjadi object :

ArrayObject Object ( [storage:ArrayObject:private] => Array ( [0] => Array ( [title] => Judul 1 [content] => Konten 1 ) [2] => Array ( [title] => Judul 3 [content] => Konten 3 ) ) )

Ini baru contoh sederhana, mungkin teman-teman bertanya-tanya, tanpa Iterator pun bisa kok menghapus index, dengan foreach array lalu unset. Sekali lagi ini hanyalah contoh. Banyak kemampuan lain jika kita menerapkan Iterator object pada collection kita. Seperti kita dapat memanipulasi data dengan mengganti current index dengan next atau prev method. Kurang lebih semuanya adalah untuk traverse (melintasi) suatu collection. Mari kita coba method lainnya :

<?php // Sebuah koleksi data artikel. $articles = [ 0 => [ 'title' => 'Judul 1', 'content' => 'Konten 1' ], 1 => [ 'title' => 'Judul 2', 'content' => 'Konten 2' ], 2 => [ 'title' => 'Judul 3', 'content' => 'Konten 3' ] ]; // Mengkonversi data array menjadi object. $articles = new ArrayObject( $articles ); // Mengimplementasikan Iterator pada array tersebut dengan method getIterator. $object = $articles->getIterator(); // Cetak index sekarang, akan mengakses index 0 yaitu Judul 1 echo 'Index sekarang : ' . $object->current()['title'] . '<br/>'; // Lalu kita coba majukan index $object->next(); // Kita cetak lagi, harusnya sekarang jadi index 2 yaitu Judul 2 echo 'Maju satu index : ' . $object->current()['title'] . '<br/>'; // Reset ke 0 $object->rewind(); // Kita cetak lagi. echo 'Setelah di reset : ' . $object->current()['title'] . '<br/>'; ?>

Outputnya seperti ini :

Index sekarang : Judul 1 Maju satu index : Judul 2 Setelah di reset : Judul 1

Bisa dipahami? suwaktu waktu pasti kita butuh method method traverse seperti ini, misalnya kita mengolah data yang lebih kompleks lagi seperti susunan array gambar.

Custom Iterator dengan Interface

Pada kode sebelumnya kita memanfaatkan class ArrayObject bawaan PHP untuk meng-enable Iterator. Simple sih, tapi tidak bisa kita custom. Nah, ada cara lain yang lebih custom untuk membuat pattern Iterator. Yaitu memanfaatkan Interface Iterator. Mari kita lihat kode berikut :

<?php /** * Pertama tama kita bikin dulu Class random dengan nama MyIterator. MyIterator ini yang akan menjadi class andalan kita untuk mengolah data. Nama class nya sebenarnya sih bebas ya. * MyIterator ini kita build dengan implements Iterator. * * Interface Iterator ini sudah bawaan mesin PHP, tidak harus kita define terlebih dahulu. Jika belum tahu Interface, coba baca dulu materi tentang Interface ya. * MyIterator ini harus menyediakan semua default interface Iterator seperti rewind, current, key, prev dst untuk kegunaan data traversing * */ class MyIterator implements Iterator { private $position = 0; private $data; public function __construct($data) { $this->position = 0; // Masukan param data ke property. $this->data = $data; } public function rewind() { $this->position = 0; } public function current() { return $this->data[$this->position]; } public function key() { return $this->position; } public function next() { ++$this->position; } public function prev() { --$this->position; } public function valid() { return isset($this->data[$this->position]); } // Method tambahan .. tidak ada pada default iterator ArrayObject. public function remove($position) { unset($this->data[$position]); } } ?>

Jika kita lihat berbagai methodnya mirip dengan cara pertama. Karena memang sama-sama implement Iterator milik PHP. Tapi disini lebih kita custom lagi dengan menambahkan method tambahan bernama remove. Tugasnya adalah menghapus index collection yang kita inginkan. Mari kita lengkapi lagi kodenya jadi seperti ini :

<?php class MyIterator implements Iterator { private $position = 0; private $data; public function __construct($data) { $this->position = 0; // Masukan param data ke property. $this->data = $data; } public function rewind() { $this->position = 0; } public function current() { return $this->data[$this->position]; } public function key() { return $this->position; } public function next() { ++$this->position; } public function prev() { --$this->position; } public function valid() { return isset($this->data[$this->position]); } // Method tambahan .. tidak ada pada default iterator ArrayObject. public function remove($position) { unset($this->data[$position]); } } // Kita punya data yang sama, mirip seperti cara pertama. Yaitu data articles. $articles = [ 0 => [ 'title' => 'Judul 1', 'content' => 'Konten 1' ], 1 => [ 'title' => 'Judul 2', 'content' => 'Konten 2' ], 2 => [ 'title' => 'Judul 3', 'content' => 'Konten 3' ] ]; // Sekarang mari kita instansiasi dengan construct data kedalam MyIterator. Sehingga nnt data array kita akan berubah menjadi object iterator. $object = new MyIterator($articles); // Passing articles. // Sekarang kita lakukan hal yang sama dengan cara pertama, yaitu traverse data. // Cetak index sekarang, akan mengakses index 0 yaitu Judul 1 echo 'Index sekarang : ' . $object->current()['title'] . "\n"; // Lalu kita coba majukan index $object->next(); // Kita cetak lagi, harusnya sekarang jadi index 2 yaitu Judul 2 echo 'Maju satu index : ' . $object->current()['title'] . "\n"; // Reset ke 0 $object->rewind(); // Kita cetak lagi. echo 'Setelah di reset : ' . $object->current()['title'] . "\n"; // Mari kita coba method remove, harusnya akan menghapus index 1 $object->remove(1); // Cetak ulang print_r($object); ?>

Pada kode diatas kita mendefine class Iterator lalu menggunakannya. Dengan menginstansiasi object dengan construct data articles. Lalu kita panggil method traverse next, rewind. Serta mencoba custom method yang sudah kita buat yaitu remove.

Outputnya :

Index sekarang : Judul 1 Maju satu index : Judul 2 Setelah di reset : Judul 1 MyIterator Object ( [position:MyIterator:private] => 0 [data:MyIterator:private] => Array ( [0] => Array ( [title] => Judul 1 [content] => Konten 1 ) [2] => Array ( [title] => Judul 3 [content] => Konten 3 ) ) )

Bisa dilihat sekarang articles membuang index ke 1 dan tersisa hanya 2 record saja.

Demikian materi tentang pattern Iterator. Tentunya materi ini baru secuil dari pembahasan Iterator. Teman-teman bisa mencoba baca sumber materi lain untuk melengkapi pemahaman tentang pattern ini. Semoga bermanfaat!