Object Cloning di PHP 5

Sunday, December 7, 2008 11:01 PM | 9 comments | 0 backlinks |

Beberapa waktu lalu sempat ada yang bertanya tentang apa efektifnya menggunakan object cloning di PHP 5. Untuk mengetahui efektifitasnya, maka mungkin ada baiknya untuk mengetahui kenapa PHP 5 support object cloning.

Jawaban gue atas thread ini, gue masukin ke blog gue sebagai referensi gue. Dan gue harap juga bisa membantu yang lain kalau sedang belajar tentang object cloning di PHP 5. Apabila ada yang perlu di koreksi, ditambahkan atau dikritik, gue terima dengan senang hati.

Pada dasarnya informasi tentang object cloning bisa dibaca di dokumentasi PHP 5. Untuk mengetahui kenapa ada clone object, perlu kita ketahui, bahwa di php 5 sekarang object itu sudah gak pass by value, tapi pass by reference.

Apa artinya itu? Mungkin bisa gue jelaskan seperti ini. Misalnya kita bekerja di sebuah gudang Laptop. Apabila kita menyimpan sebuah laptop, maka kita dapat secarik kertas kecil yang berisi catatan laptop tersebut ada di bagian mana di gudang. Misalnya Blok 5, Rak 3, Kotak nomer 8. Catatan ini kita bisa istilahkan sebagai "referensi" kita pada obyek laptop tersebut.

Apabila kita ingin memberikan obyek tersebut kepada orang lain (variabel lain). Maka kita sebenarnya membuat fotokopi dari catatan kita, dan memberikannya kepada orang tersebut. Disini kita lihat, kita hanya mengkopi "referensi" kita. Obyeknya tetap mengacu pada laptop yang sama. Artinya apabila orang lain melakukan perubahan pada laptop tersebut, maka sewaktu kita melihat kembali laptop tersebut, kondisinya sudah berubah.

Object Cloning dalam contoh ini berarti. Kita membuat satu cloning dari laptop tersebut. Bentuk dan kondisinya sama persis. Akan tetapi, karena Kotak nomer 8 pada Rak 3 di Blok 5 sudah diisi sama laptop pertama tadi, maka laptop cloningan ini harus ditaruh di kotak yang lain. Misalnya saja Kotak nomer 2 pada Rak 4 di Blok 5. Setelah itu kita membuat catatan kecil tentang alamat laptop tersebut, dan memberikannya pada teman kita. Dengan ini apabila teman kita melakukan perubahan pada laptop tersebut, dia tidak merubah laptop (obyek) kita, tapi laptop kloningan.

Sekarang mari kita coba mengggunakan contoh code.
<?php
class Account {
    public $balance;

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

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

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

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

    function getId() {
        return $this->id;
    }

    $account = new Account(0);
    $person = new Person('Oka', 21, $account);
    $person->setId(2);
    $person2 = $person;
    $person2->setId(4);
    echo $person->getId().' '.$person2->getId();
?>

Di PHP 4 hasil dari echo tersebut adalah "2 4"; Akan tetapi di PHP 5 hasil dari echo tersebut adalah "4 4"; ini disebabkan di PHP 5 pada statement $person2 = $person object Person pada $person di pass by reference ke $person2, dalam arti di dalam variable $person2 isinya bukan copy (clone) dari object $person, tapi isinya hanyalah sebuah pointer yang menunjuk ke memory, dimana object $person di simpan.

Oleh karena itu setiap perubahan yang dilakukan di object $person2 akan ikut mempengaruhi object $person. Kenapa dibuat seperti ini di php5? nampaknya php5 berusaha untuk menyamakan behaviour syntax nya pada bahasa2 berparadigma OOP lainnya. CMIIW. supaya orang yang biasa kerja di java, .net atau sejenisnya tidak kaget waktu kerja ber OOP pakai PHP dan sudah biasa dengan asumsi bahwa statement "=" untuk object itu, pasti parse by reference.

Tambahan info. Dalam bahasa pemrogramman berorientasi obyek. Biasanya orang mengenal tipe data "primitiv" dan tipe data "obyek". Tipe data primitiv seperti integer itu selalu pass by value, sedangkan tipe data obyek itu pass by reference. Oleh karena ini, apabila kita di PHP5 ingin memiliki copy utuh dari sebuah object, dimana apabila kita merubah state dari object kopian tersebut tidak mempengaruhi object aslinya, kita diberikan solusi clone.

Mari kita coba merubah code gue diatas dengan clone:
<?php
$account = new Account(0);

$person = new Person('Oka', 21, $account);

$person->setId(2);

$person2 = clone $person;

$person2->setId(4);

echo $person->getId().' '.$person2->getId();
?>

Dengan ini di PHP 5 hasil echonya bisa sama dengan PHP 4 yaitu "2 4". Di thread milist ada yang bertanya, kenapa gak di instance ulang saja seperti ini?
<?php
$person = new Person("Oka", 21, new Account(200));
$person2 = new Person("Oka", 21, new Account(200));
$person3 = new Person("Oka", 21, new Account(200));
?>

Mari kita lihat keefektivan dari clone. Dengan clone kita mendapat copy yang sama persis dari object yang di clone. sedangkan contoh pada contoh diatas, untuk membuat 3 object yang statenya sama, kita harus memasukkan kembali nilai dari parameter tersebut.

Kasusnya mungkin bisa seperti ini. Bayangkan kalau object $person yang kita bikin itu mau digunakan di sebuah class yang bukan tanggung jawab kita. Misalnya (lagi2) kolega kerja kita.

Bekerja Object Oriented yang baik adalah dimana kolega kerja kita tidak perlu tahu menahu seluk beluk yang terjadi di dalam object yang kita bikin (loose coupled). Bisa jadi misalnya, ini misal ya, bahwa state dalam object tersebut seperti nama, umur dan account balancenya didapat dari $_POST (informasi yang diberikan user lewat user interface). Dan karena satu dan lain hal, kolega kita tidak bisa membaca atau tidak tahu menahu soal $_POST. Yang dia tahu hanya object yang di dapat dari kita. Satu-satunya state yang bisa dia ganti misalnya adalah Id nya dengan menggunakan public method setId().

Disini dia gak punya lagi kesempatan untuk bikin instance baru dari class Person yang statenya sama persis sama object $person yang kita berikan. Dia kan gak tahu bahwa waktu menginstance object $person kita memberikan nilai "Oka", 21 dan account balance 200 pada masing2 class attributenya. Maka dari itu, digunakanlah tehnik clone ini.

Mari kita coba ya pakai contoh code. Sebagai contoh kita bertanggung jawab untuk UI (Presentation Tier), dan kolega kita yang bertanggung jawab di bagian Database (Persistent Tier).
<?php
$person = new Person ($_POST['name'], $_POST['age'], new
Account($_POST['balance']));
$person->setId($_POST['id']);

$persistancePerson->insertNewPerson($person);
?>
Sampai disini tugas kita kelar dan kita memberikan object $person kepada kolega kita yang ngurusin insert ke database. Soal SQL statement mah dia jagonya lah, kita gak peduli. Nah sekarang sebelum die melakukan insert ke database, dia pengen coba-coba dulu periksa, udah ada belon data dengan id tersebut di database, kalau memang sudah ada maka akan diberikan id baru, lalu di save. Supaya dia gak mengganggu object state yang diterima dari kita, maka untuk coba-coba, dia bikin clone dari object tersebut.

Misalnya isi dari methode insertNewPerson(Person $person) seperti berikut:
<?php
public function insertNewPerson(Person $person){
   $person2 = clone $person;

  while($this->idAlreadyExist($person2->getId())){
         $person2->setId($this->getNextId());
  }

  $DBObject::getInstance()->execute('INSERT INTO person ......');
}
?>

Dengan ini dia mencoba-coba menggunakan object kopian dari $person. Pada $person2->setId() hanya object $person2 saja yang terganti statenya. Object $person tetap seperti sediakala, sewaktu dia menerima dari kita.

Manakah yang lebih cepat, membuat instance baru, atau mencopy. Disini kita bisa membaca kembali dokumentasinya. Disitu ditulis:

When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties. Any properties that are references to other variables, will remain references.

Menurut pemahaman gue tentang Computer system, untuk bikin instance baru itu pasti lebih ribet, mungkin ngecheck nilai dari parameternya bener tidak, nama classnya exist tidak, terus generate segalanya dalam bentuk object, lalu cari memory yang kosong untuk di simpan. Kalau copy object kan dia gak perlu ngejalanin semuanya itu. tinggal cari memory kosong, terus kopi ajah mentah-mentah (shallow copy) dari memory object aslinya.

Gue harap informasi ini bisa memberikan pencerahan.

Pengecualian di PHP 5

9:00 PM | 7 comments | 0 backlinks |

Beberapa waktu lalu di milist id-php ada yang sempat bertanya tentang Exception di PHP 5. Beberapa contoh yang diberikan, menurut gue masih kurang menunjukkan kemampuan dari exception itu sendiri, maka dari itu gue mencoba untuk ikutan memberikan jawaban dan contoh.

Tulisan gue di milist, gue coba tulis kembali di blog gue, untuk sekedar jadi arsip gue. Mungkin juga bisa membantu yang lain apabila ada yang cari-cari informasi tentang exception di PHP 5. Beberapa dari contoh yang gue kasih di tulisan gue waktu itu gue perbaiki karena ada kesalahan di syntaxnya. Apabila masih ada yang perlu di koreksi atau kritik dan saran, gue terima dengan senang hati.

Secara umum penggunaan exception bisa dibaca di dokumentasi PHP 5. Beberapa dari contoh yang disebutkan di milist, menunjukkan bahwa exception dapat digunakan untuk melihat backtrace error. Memang benar dengan exception kita bisa melihat backtrace error dari programmnya. Tapi untuk backtrace sendiri PHP sebenarnya sudah punya debug_backtrace.

Bukan berarti kita tidak boleh menggunakan Exception untuk melakukan backtrace. Tentu saja boleh, malah kalau kita bekerja menggunakan orientasi obyek, kita justru dipermudah dalam hal backtrace menggunakan Exception. Akan tetapi gue pengen kasih contoh tujuan yang sebenarnya dari exception itu sendiri.

Sebelum itu gue mau mencoba mengutip satu contoh yang diberikan di milist dalam thread ini.
<?php
if (!is_writable($this->file)) {
    throw new Exception("file '{$file}' is not writeable");
}
file_put_contents($file,$xmlObj->asXML());

//apa bedanya klo saya buat seperti ini ? :
if (!is_writable($this->file)) {
    echo "Aduuwwhhh filenya ndak bisa ditulisi!";
    exit();
}
file_put_contents($file,$xmlObj->asXML());`
?>
Contoh tersebut membuat PHP mengeluarkan error message "uncaught exception". Ini sebenarnya sebuah error yang tidak boleh ada. Kalau di java, hal seperti ini membuat code java nya sendiri gak bisa di compile, sampai sang programmer membuat try-catch block pada programm code yang berpotensi untuk melempar exception tersebut.

Seperti yang gue bilang diatas, kita bisa menggunakan exception, sebagai error handler, tapi bukan berarti exception itu melulu merupakan sebuah "error". Dengan exception kita diberi kesempatan untuk melakukan sesuatu (handle) terhadap exception tersebut.

Gue akan memberikan contoh yang mengacu pada contoh diatas. Dan gue coba berikan sebuah skenario dimana penggunaan exception bisa digunakan.

  • Gue harus membuat sebuah methode (dalam class) yang dapat menulis xml kedalam sebuah file.
  • Untuk menulis file kedalam xml, maka gue butuh 2 parameter, yaitu file, dan string.
  • Parameter file tersebut harus sebuah file resource, harus bisa dibaca dan harus bisa ditulis.
  • Parameter string tersebut harus sebuah string, dan merupakan xml yang conform.
  • Apabila semua prosedur itu dipenuhi maka xml tersebut bisa ditulis kedalam file.
Berikut adalah contoh kelasnya.
<?php
class PutXMLToFile{

   public function putThatThing($file, $xml){
        if(!is_file($file)){
           throw new ExceptionIsNotAFile('Resource is not a File!');
        }

        if(!is_readable($file)){
           throw new ExceptionFileNotReadable('File not readable.');
        }

        if(!is_writeable($file)){
           throw new ExceptionFileNotWriteable('File not writeable');
        }

        if(!is_string($string)){
           throw new ExceptionIsNotAString('not a string');
        }

        if(!is_xml_conform($string)){
           throw new ExceptionIsNotXMLConform('not xml conform');
        }

        file_put_contents($file,$string);
   }
}
?>
Dengan ini kita akan memberikan code ini - misalnya - kepada kolega kerja kita, yang bertanggung jawab untuk user interface. Katakanlah ada 2 kolega kita yang bertanggung jawab untuk UI, yang satu UI untuk browser biasa, yang satu UI untuk mobile browser.

Requirementnya sebagai berikut.
  • Apabila file, bukan sebuah file, maka buka UI file management untuk memilih atau mengupload file.
  • Apabila file tidak dapat dibaca, atau tidak dapat ditulis, maka buka UI file access management untuk mengedit file access.
  • Apabila string bukan string, tampilkan error message.
  • Apabila string tidak xml conform, maka tampilkan UI xml editor untuk mengedit xml file tersebut.
Sekarang gue bukin contoh untuk UI mobile browser. Gue anggap user interface object nya sudah jadi saja.
<?php
$userInterface = new MobileUserInterface();

try{
   $putXMLToFile = new PutXMLToFile();
   $putXMLToFile->putThatThing($file, $string);
}catch (ExceptionIsNotAFile $e){
    $userInterface->openFileManager();
}catch (ExceptionFileNotReadable $e){
     $userInterface->openFileAccessManager();
}catch (ExceptionFileNotWriteable $e){
     $userInterface->openFileAccessManager();
}catch (ExceptionIsNotAString $e){
     $userInterface->showError($e->getMessage());
}catch (ExceptionIsNotXMLConform $e){
     $userInterface->openXMLEditor();
}
?>
Seperti yang bisa kita lihat, fungsi pada contoh pertama untuk put xml to file jadi lebih loose coupled dan mudah diimplementasikan di berbagai macam kebutuhan. Kolega kita yang ingin mengerjakan UI untuk browser biasa misalnya bisa melakukan seperti code diatas, hanya saja object nya bukan new MobileUserInterface() tapi new StandardUserInterface() misalnya.

Dalam try{} block kolega kita juga bisa untuk tidak hanya menulis code yang akan menangkap exception dari object kita, tapi juga dari object lain. Dalam arti di dalam try{} block bisa terjadi algoritma yang cukup komplex.

Misalnya saja requierement yang diatas ditambahkan lagi:
  • Setelah berhasil put xml to string, maka save informasi tersebut ke dalam database,
  • lalu kirimkan email kepada orang yang bersangkutan.
Database object dan email object, bisa jadi memiliki exception mereka sendiri yang sudah selayaknya ditangkap entah itu connection not avaliable, column or table not exist, database not exist, sql statement syntax error dan sejenisnya.

Pada email object bisa jadi, mail server not responding, atau email address invalid atau email address not exist in database, dan sejenisnya.

Exception tersebut juga bisa ditangkap dan dilakukan sesuatu(handle) terhadap exception tersebut. Bisa jadi hanya menampilkan error. Tapi seperti contoh di atas, tidak selalu exception itu merupakan sebuah error. Berikut adalah contoh pengembangan code yang diatas:
<?php
$db = DBObject::getInstance();

try{
   $putXMLToFile = new PutXMLToFile();
   $putXMLToFile->putThatThing($file, $string);

   $db->beginTransaction();
   $modelSomething->insertSomething();
   $modelAnything->updateAnything();

   $email = Email::getInstance();
   $email->setTo($emailAddressTo);
   $email->setSubject($emailSubject);
   $email->setMessage(emailMessage);
   $email->send();

   $db->endTransaction();

}catch (ExceptionIsNotAFile $e){
    $userInterface->openFileManager();
}catch (ExceptionFileNotReadable $e){
     $userInterface->openFileAccessManager();
}catch (ExceptionFileNotWriteable $e){
     $userInterface->openFileAccessManager();
}catch (ExceptionIsNotAString $e){
     $userInterface->showError($e->getMessage());
}catch (ExceptionIsNotXMLConform $e){
     $userInterface->openXMLEditor();
}catch (ExceptionDBException $e){
     $db->rollbackTransaction();
     $userInterface->showError($e->getMessage());
}catch (ExceptionEmailException $e){
     $db->rollbackTransaction();
     $userInterface->showError($e->getMessage());
}
?>
Semoga tulisan gue bisa memberi sedikit pencerahan.

Konsep Visibility pada PHP 5

6:46 PM | 0 comments | 0 backlinks |

Beberapa waktu lalu di milist PHP-UG ada yang nanya tentang konsep Visibility pada PHP 5. Banyak juga yang sudah menjawab. Dan menurut gue jawabannya juga bagus-bagus. Tapi gue juga ikutan jawab, karena sebagian besar jawabannya tidak mengacu pada konsep dasar tentang Visibility secara umum dalam pemrograman berorientasi objekt.

Tulisan gue di milist, gue masukin di blog sebagai arsip gue pribadi. Mungkin juga berguna buat yang lain kalau-kalau satu saat ingin cari tahu mengenai konsep visibility. Kalau ada kritik, koreksi atau tambahan, tentunya gue dengan senang hati menerima.

Secara umum penggunaan Visibility pada PHP 5 bisa dilihat langsung di dokumentasinya PHP 5. Setelah kita tahu bagaimana visibility berfungsi pada function, atau member variabel, gue rasa penting juga sebenarnya bertanya, kenapa sebenarnya ada visibility? Kapan pakainya? Buat kalian yang beranjak dari PHP < 5, maka pertanyaan yang sebenarnya juga cukup menarik, kenapa PHP sekarang support visibility?

Private, public, protected merupakan bagian dari prinsip "information hiding" dalam ilmu komputer. Kalau ingin tahu apa itu prinsip "information hiding" silahkan lihat di wikipedia.

Disitu hanya dijelaskan secara gamblang saja. Ada banyak sekali hal yang bersangkutan dengan "information hiding", dan pada kesempatan ini gue pengen coba untuk menjelaskan hanya pada bagian visibility.

Menjelaskan topik informatika paling enak pake analogi, jadi gue berusaha beranalogi. Gue coba2 cari di google analogi yang lebih pas, tapi gue gak ketemu. Kalau ada yang bisa memberikan analogi yang lebih pas, silahkan dibagi ^^.

Analogi gue kali ini adalah mobil. Mobil punya setir, punya starter, punya perseneling, dan minimal punya pedal gas dan rem (kopling untuk transmisi manual). Semua mobil punya "fungsi" ini. Dan semua pengemudi tahu dan "berharap" bahwa fungsi tersebut ada di dalam sebuah mobil. Keberadaan fungsi2 tersebut dalam sebuah mobil bisa kita lihat sebagai bentuk "public visibility".

Mobil bisa jalan karena ada mesinnya. Masalahnya disini adalah, bagaimana bentuk mesinnya, bagaimana cara kerjanya. atau. apakah sebenarnya mobil tersebut jalan pakai mesin? Hal itu semua sudah bukan urusan pengemudi mobil. Hal itu sudah urusan perusahaan yang bikin itu mobil. Bisa jadi mas Joko Suprapto punya methode lain buat bikin mobil bisa jalan ^^ (Ilmu gaib mungkin? ^^ ).

Fungsi mesin tidak hanya sekedar urusan perusahaan, akan tetapi mesin merupakan bagian paling penting dari inovasi perusahaan. Apakah mobil tersebut bisa ngebut, irit bensin, tidak berisik, ramah lingkungan, semuanya ditentukan dari kerja mesin tersebut. Karena semua jerih payah berpikir para insinyur automobile ada di dalam situ, perusahaan melindungi informasi tersebut, dan ingin agar fungsi tersebut tidak digunakan untuk kepentingan lain, selain untuk menjalankan mobil, ^^ dengan menggunakan fungsi2 "publik" yang sudah didefinisikan (setir, perseneling, pedal, dsb). Pokoknya pengemudi hanya tahu, untuk jalanin sebuah mobil, kudu starter dulu, masukin perseneling. dan kalo injek gas, mobilnya jalan, kalo di rem berhenti. Fungsi mesin disini bisa kita lihat sebagai bentuk "private visibility".

Perusahaan pembuat mobil tahu, bahwa dia gak akan bisa membuat mobil yang sesuai sama selera seluruh umat manusia ^^. Yang satu ingin mobilnya lebih nyaman, yang satu pengen bisa lebih cepat, yang satu ingin lebih irit, yang satu ingin lebih ramah lingkungan, dan lain sebagainya. Maka dari itu perusahaan pembuat mobil membuat beberapa komponen mobil memiliki kesempatan untuk di expand atau dimodifikasi. Entah itu pasang AC, pasang, Nitro, pasang katalisator, ganti jok mobil, ganti velg, diceperin dan lain sebagainya. Spesifikasi dan informasi komponen-komponen yang bisa di expand atau dimodifikasi tersebut diberikan oleh perusahaan mobil, ke bengkel2 mobil. Apakah itu bengkel resmi ato bukan untuk sementara tidak relevan ^^.

Seperti halnya mesin pada perusahaan mobil. sebagai pengemudi, kita tetap tidak tahu menahu tentang komponen ini. Kita tetap hanya mengetahui fungsi-fungsi publik. Kita tetap mengendarai mobil seperti biasanya. Hanya saja mobil kita mungkin sekarang lebih cepat, lebih irit, lebih nyaman, atau lebih-lebih yang lainnya. ^^. Analogi yang ini bisa kita lihat sebagai bentuk "protected visibility".

So itu analoginya visibility. Kalo dilihat dari subject threadnya ada yang nanya tentang visibility jenis "global". Jenis itu sepertinya spesifik di php doang, dimana function berdiri sendiri, tidak dalam sebuah kelas. CMIIW. Agak sulit menganalogikannya dalam kasus mobil diatas, karena paradigma object oriented itu melihat semuanya berupa object. Kalau gue memisalkan fungsi dengan visibility "global" sebagai kunci stang (yang jaman dulu tuh, yang buat dipasang dari setir ke pedal, tauk deh ada yang bisa bayangin kah) gak bisa juga. Karena kunci stang adalah object ^^ yang punya fungsi yaitu - seperti namanya - ngunci setir. ^^

Setelah panjang berteori fundamental visibility pada pemrogramman berorientasi obyek. sekarang mari kita coba menjawab pertanyaan kenapa ada visibility? Kapan pakainya, dan kenapa PHP sekarang support visibility?

PHP berkembang dari sekedar Personal Home Page pre-processor tools yang dibuat Rasmus Lerdorf, menjadi sebuah Full Blown Web Application language. Gue gak bilang enterprise ^^, karena untuk menjadikannya enterprise gak cukup pengetahuan PHP doang seperti layaknya sodara kita di java dan .net ^^.

Untuk membuat aplikasi, banyak komponen2 yang akan sering digunakan berulang-ulang di setiap project. Daripada setiap kali harus tulis ulang, mendingan dipakai lagi. Muncullah berbagai macam jenis framework di PHP yang umumnya punya tujuan yang sama, yaitu membuat pembangunan aplikasi web menjadi lebih cepat, mudah, dan bug free.

Membuat framework, sama halnya dengan membuat mobil, para developer framework menentukan melalui fungsi apa framework tersebut digunakan (public), fungsi-fungsi apa yang critical dan tidak boleh digunakan untuk kepentingan lain (private), dan fungsi-fungsi apa yang punya kemungkinan untuk di expand atau diganti (protected). Pengguna framework hanya akan dihadapkan dengan fungsi2 yang memiliki visibility public dalam membangun web aplikasinya.

Karena visibility baru di support setelah PHP 5, pembuatan framework memiliki problem dalam penggunaan visibility. Untuk mengantisipasi hal ini, Segala macam bentuk code convention digunakan dalam komunitas framework. Salah satunya adalah PEAR convention yang memberikan tanda strip bawah ( _ ) untuk setiap private member variabel dan private method.

Framework gak selalu harus pakai punya orang. Buat mereka yang bekerja product developing, umumnya punya methode dan fungsi2 proprietary yang juga digunakan dalam pekerjaan sehari-hari. Dalam hal ini bisa jadi masing-masing memiliki code convention sendiri-sendiri.

Sekarang gue mo coba memberikan contoh praktis dalam bentuk code untuk belajar memahami kapan menggunakan dan memilih visibility. Code ini jauh dari sempurna dalam konteks design-nya. Diantara kalian pasti bisa membuat yang jauh lebih baik dari ini. Akan tetapi menurut gue ini bagus untuk membantu memahami prinsip visibility.

Gue mau tetap bergerak di lingkup analogi gue, yaitu mobil. Gue mau membuat sebuah kelas "mobil". Untuk bisa memahami lebih baik, perlu diketahui bahwa dalam bekerja menggunakan paradigma berorientasi obyek, programmer harus berpikir bahwa code yang dia tulis suatu saat akan "digunakan" oleh orang lain, gue kasih tanda kutip, karena maksudnya disini bukan dimodifikasi atau dirubah.

Untuk itu gue buat skenario sebagai berikut.

Kelas mobil yang gue tulis disini adalah bagian dari sebuah aplikasi game. Anggap saja game balap mobil. Tanggung jawab gue adalah menulis kelas mobil ini dan kelas ini satu saat nanti akan digunakan oleh kolega kerja gue yang memprogramm kelas "pengemudi". Untuk itu gue udah berdiskusi sama dia, apa fungsi yang harus ada, yang perlu dia ketahui. lalu sama2 bikin daftarnya.
  • Fungsi setir. Menerima informasi kiri atau lurus atau kanan (-1, 0 atau 1)
  • Fungsi startEngine. Mengirimkan informasi kembali apakah mesin berhasil di starter (true atau false)
  • Fungsi stopEngine. mengirimkan informasi kembali apakah mesin berhasil dimatikan (true atau false)
  • Fungsi setPerseneling. menerima informasi perseneling (0 sampai 5)
  • Fungsi gas. menerima informasi tekanan seberapa besar gas diinjak (0-5)
  • Fungsi rem. menerima informasi tekanam seberapa besar rem diinjak (0-5)
So cukup. Sisanya dia gak perduli bagaimana gue mengimplementasikannya. Dia sebenarnya juga tidak berhak tahu ^^. Tapi gue berpikir agak jauh ke depan. bisa jadi code gue nanti bagus dan ingin terus dipakai, tapi karena satu dan lain hal, beberapa komponen sudah tidak begitu relevan lagi, baik itu kurang bagus, kurang cepat, atau kurang-kurang yang lainnya. Untuk itu gue akan mencoba mendefinisikan komponen apa yang kira-kira bisa diganti atau ditambah.

Setelah berpikir, maka gue menulis daftarnya.

  • Fungsi tangkiBensin
  • Fungsi knalpot
  • Fungsi airConditioner
So setelah ini kalo ada fungsi lain yang gue butuh, gue bebas berkreatifitas. Mau berapa banyak kek fungsinya dan namanya apa. Itu sudah terserah gue. Sekarang mari kita buat kelasnya.

class Mobil{

   private $engineStart = false;
   private $warna = 'putih';
   private $brand = 'bmw';
   private $perseneling = 0;

   public function __construct(){
       echo 'objek mobil dibuat';
       $this->tangkiBensin();
       $this->airConditioner();
       $this->knalpot();
   }

   public function setWarna($warna){
       $this->warna = $warna;
   }

   public function getWarna(){
       return $this->warna;
   }

  public function setBrand($brand){
      $this->brand = $brand;
  }

  public function getBrand(){
      return $this->brand;
  }

  public function engineStart(){
      $this->engineStart = true;
  }

  public function engineStop(){
      $this->engineStart = false;
  }

  public function isEngineStart(){
      return $this->engineStart;
  }

  public function setPerseneling($perseneling){
      $this->perseneling = $perseneling;
  }

  public function gas($gas){
      echo "nge-gas dengan tekanan pedal ".$gas;
      $this->knalpot();
  }

  public function rem($rem){
     echo "nge-rem dengan tekanan pedal ".$rem;
  }

  public function setir($arah){
       switch($arah){
            case -1:
                $this->moveLeft();
                break;
            case 0:
                $this->moveStraight();
                break;
           case 1:
                $this->moveRight();
                break;
           default:
                throw new Exception('hanya bisa 
                      menerima nilai -1, 0 atau 1');
       }
  }

  protected function tangkiBensin(){
        echo "tangki bensin muat 60 liter";
  }

  protected function knalpot(){
       echo "knalpot standard";
  }

 protected function airConditioned(){
     echo "gak punya AC";
 }

 private function moveLeft(){
     //TODO: implement how to move left
 }

 private function moveRight(){
     //TODO: implement how to move right
 }

 private function moveStraight(){
     //TODO: implement how to move Straight
 }

}
Okay, mari kita lihat dengan seksama. Pertama-tama member variabel. Gue nambahin warna dan brand, hanya sekedar tambahan saja untuk mendefinisikan personalitas sebuah objekt. Yang mau gue tunjukin disini adalah penggunaan visibility private pada getter dan setter (misal setBrand dan getBrand).

Tentu saja kita bisa pasang visibility apa saja pada member variabel. Tapi sudah merupakan best practice, bahwa member variabel itu sebaiknya private atau protected, dan member variabel tersebut hanya bisa dibaca dan ditulis melalui getter dan setter methodenya (kalo gue gak salah, best practice ini pelopornya java beans CMIIW). Apa alasannya? Dengan ini kita memiliki kontrol penuh atas nilai yang diberikan kepada member variabel tersebut. Sebagai contoh, apabila kita hanya punya warna atau merk tertentu, kita bisa bikin validator di dalam set methode untuk menentukan apakah warna yang diberikan pada argument tersebut valid atau tidak.

Mungkin contoh warna dan merk tidak begitu critical. Tapi coba bayangkan kalau perseneling member variabel gue pasang public, terus temen gue pasang angka 6, dengan cara $mobilObj->perseneling = 6; padahal mobil gue cuma bisa nerima sampe 5. Gue gak mau bayangin apa yang akan terjadi ^^. Apabila memang dibutuhkan, maka gue dengan mudah bisa implementasikan if atau switch statement di methode setPerseneling untuk menghindari hal seperti ini.

Selain itu, untuk perseneling, gue gak memberikan methode getPerseneling. dalam hal ini, gue gak punya alasan konkrit. Tapi bisa saja terjadi dalam pekerjaan, bahwa kita tidak mau orang membaca kembali nilai yang sudah dia berikan ^^.

Seperti yang bisa dilihat, gue membuat fungsi tangkiBensin, knalpot dan airConditioned sebagai protected karena gue merasa bagian itu satu saat bisa di modifikasi oleh orang lain. Sisanya fungsi moveLeft, -Right, dan -Straight merupakan contoh implementasi gue tentang bagaimana gue menjalankan mobil. Mungkin bisa lebih dari ini fungsinya. Tapi ini sekedar contoh saja. Fungsi ini digunakan oleh methode setir dimana dia memvalidasi argument yang diberikan menggunakan switch statement, dan melempar exception apabila argument tersebut tidak valid.

Exception gak akan gue jelasin disini ^^, jadi makin banyak entar ^^. Gue sudah pernah jelasin tentang exception deh ^^.

Setelah kelas mobil gue kelar, gue kasih ke temen gue. Dan akhirnya dia bisa pake deh. Bagaimana dia makenya, kira2 begini:
class Pengemudi{

      //member variabel pengemudi
      private $mobilObj;

     //lots of code implementing pengemudi

    public function setMobil(Mobil $mobilObj){
        $this->mobilObj = $mobilObj;
    }

    public function nyetirUgalUgalan(){
         if(!$this->mobilObj->isEngineStart()){
              $this->mobilObj->engineStart();
         }
         $this->mobilObj->setPerseneling(1);
         $this->mobilObj->gas(5);
         try{
             $this->mobilObj->setir(-1);
             $this->mobilObj->setir(1);
             $this->mobilObj->setir(-1);
             $this->mobilObj->setir(1);
         }catch(Exception $e){
             echo $e->getMessage();
             print_r($e->getTrace());
         }
         $this->mobilObj->rem(5);
         $this->mobilObj->setPerseneling(0);
         $this->mobilObj->engineStop();
    }

}
Ok gue harap semua tahu apa yang code diatas lakukan. Sedikit informasi, bahwa gue melakukan Type Hinting pada methode setMobil. Untuk jelasnya bisa baca dokumentasinya PHP. Type Hinting berguna sekali, membuat code jadi lebih robust dan stabil. Di tempat lain (biasanya istilahnya controller atau main methode kalo di java, di php katakanlah index.php) ada code yang membuat objekt sang pengemudi, membuat objekt mobil dan memberikannya kepada si pengemudi. Kira-kira begini:
$mobilObj = new Mobil();
$mobilObj->setWarna('orange');
$mobilObj->setBrand('Metro Mini');
$pengemudi = new Pengemudi();
$pengemudi->setMobil($mobilObj);
$pengemudi->nyetirUgalUgalan();
Di kemudian hari, kelas gue sudah mulai banyak dipakai di dalam system. Akan tetapi system tersebut butuh satu mobil lagi. Bedanya sekarang, mobil tersebut harus pasang AC, punya knalpot remus ^^ dan tangki bensin nya bisa isi 100 liter. Lebih canggihnya lagi, mobil tersebut gak cuma bisa belok ke kiri, kanan dan lurus, tapi sekarang bisa keatas dan kebawah (bisa terbang ^^. Ga usah protes. Suka-suka gue. Aplikasi gue kok :P). Mobil tersebut akan digunakan oleh pengemudi baru yang jauh lebih berpengalaman. Istilahnya sekarang "pilot". Mobil-mobil yang sudah dimiliki oleh pengemudi lainnya tidak boleh diganggu-gugat. Mereka sudah senang dengan keadaannya tersebut (prinsip never touch a running system). So apa yang gue lakukan? Gue akan bikin satu class mobil baru yang mewarisi fungsi-fungsi class mobil gue yang lama. Yang suka pake bahasa inggris, pasti kenal yang istilahnya inheritance.^^

So mari, coba kita bikin.
class MobilBaru extends Mobil{

  public function setir($arah){
       switch($arah){
            case -1:
                $this->terbang('kiri');
                break;
            case 0:
                $this->terbang('kanan');
                break;
           case 1:
                $this->terbang('atas');
                break;
           case -2:
                 $this->terbang('bawah');
                 break;
           case 2:
                 $this->terbang('lurus');
                 break;
           default:
                throw new Exception('hanya bisa menerima nilai -2,
-1, 0, 1 atau 2');
       }
  }

  protected function tangkiBensin(){
        echo "tangki bensin muat 100 liter";
  }

  protected function knalpot(){
       echo "knalpot remus";
  }

 protected function airConditioned(){
     echo "pake AC Central Daikin ^^";
 }

 private function terbang($arah){
     //TODO: implement how to fly
 }

}
So mari kita cerna pelan-pelan. Code gue sekarang agak lebih sedikit. Kenapa? Karena sebagian besar fungsi, sudah di implementasikan di parent class. Bahkan gue ga nulis constructor. Yang gue lakukan adalah memodifikasi methode sesuai tugas gue. Perhatikan bahwa gue meng-override methode setir, tangkiBensin dan knalpot. Perlu diperhatikan disini, apabila gue melakukan override pada methode setir, maka fungsi setir disini tidak dapat membaca private method yang ada di kelas mobil. Ini bukan sesuatu yang buruk, tapi justru baik. Karena private methode tersebut diperuntukkan khusus pada kelas Mobil.

Sekarang kita membuat kelas MobilBaru dimana behaviornya berbeda sekali (bisa terbang ^^) meskipun masih masuk definisi mobil. Maka dari itu, bagaimana setir di implementasikan supaya mobil tersebut bisa bersikap sesuai yang diharapkan (terbang ^^), ditulis method baru, dan diberikan visibility private.

Disini sebenarnya, sekali lagi bebas saja mau berapa methodenya, namanya apa, dsbnya. Sebagai contoh gue bikin satu methode namanya terbang. Sekarang bagaimana bentuk kelas pengemudinya? yaa kira2 begini lah:
class Pilot{

      //member variabel pilot
      private $mobilObj;

     //lots of code implementing pilot

    public function setMobil(MobilBaru $mobilObj){
        $this->mobilObj = $mobilObj;
    }

    public function terbangUgalUgalan(){
         if(!$this->mobilObj->isEngineStart()){
              $this->mobilObj->engineStart();
         }
         $this->mobilObj->setPerseneling(1);
         $this->mobilObj->gas(5);
         try{
             $this->mobilObj->setir(1);
             $this->mobilObj->setir(-2);
             $this->mobilObj->setir(1);
             $this->mobilObj->setir(-2);
         }catch(Exception $e){
             echo $e->getMessage();
             print_r($e->getTrace());
         }
         $this->mobilObj->rem(5);
         $this->mobilObj->setPerseneling(0);
         $this->mobilObj->engineStop();
    }

}
So sekarang agak ribet. Mohon dicerna pelan-pelan. Perhatikan pada setMobil, type hint gue sekarang MobilBaru, artinya, object yang dioper pada argument cuma boleh berupa instanz dari kelas MobilBaru. Ini berguna sekali. Coba bayangkan kalau type hint nya tetap Mobil. Dia bakal sama sekali gak protes, ketika tuh pilot kita kasih objekt MobilBaru karena MobilBaru adalah sebuah mobil ^^ (inherit class Mobil). Berikutnya, waktu kita kasih dia object Mobil, pada bagian setMobil(), dia masih gak protes, karena Mobil adalah sebuah mobil (astaga...). Tapi giliran dia mo terbangUgalUgalan(). Mobilnya bakal protes. kenapa? karena dia gak mengenal argument -2 ^^. Kalo masih bingung. mari kita lihat code yang menggunakan kelas ini :
//Mari kita anggap methode setMobil pada kelas Pilot bentuknya begini:
//   public function setMobil(Mobil $mobilObj){
//        $this->mobilObj = $mobilObj;
//    }

//Perhatikan type hint nya Mobil.

//so sekarang main method atau controller atau index.php nya

$mobilObj = new MobilBaru();
$mobilObj->setWarna('orange');
$mobilObj->setBrand('Metro Mini');
$pengemudi = new Pilot();
$pengemudi->setMobil($mobilObj);
$pengemudi-> terbangUgalUgalan(); // << No error

$mobilObj = new Mobil();
$mobilObj->setWarna('orange');
$mobilObj->setBrand('Metro Mini');
$pengemudi = new Pilot();
$pengemudi->setMobil($mobilObj);
$pengemudi-> terbangUgalUgalan(); // << error: 
                                  // hanya bisa menerima
                                  // nilai -1, 0 atau 1
So gue sudah selesai. panjang juga ya? ^^ Sekali lagi, gue harap semoga bermanfaat.

File Upload Progress dengan PHP 5 dan APC

Wednesday, July 16, 2008 9:18 AM | 5 comments | 0 backlinks |

Beberapa hari lalu, secara nggak sengaja gue baca-baca PHP 5.2.0 Release Announcement (tumben ^^) dan ngelihat kalimat ini di daftar key features nya "Hooks for tracking file upload progress were introduced". Ho ho ho was ist das? Penasaran banget, gue coba tanya-tanya kang google, dan mampir di satu blog yang bertanya di PHP Development mailing list tentang fungsi tracking yang dijanjikan tersebut. Yang menjawab tidak lain dan tidak bukan adalah Rasmus Lerdorf sendiri, dan menyatakan bahwa fungsi tersebut masih berada pada level C dan membutuhkan fungsi pendukung untuk digunakan dalam php.

Sudah lama gue coba cari-cari cara untuk bisa menampilkan laporan tentang kemajuan proses sewaktu meng-upload file. Gue sebenarnya cari cara, dimana menulis codenya itu murni dalam PHP. Tapi sayangnya kebanyakan yang gue temuin itu menggunakan cgi dan ditulis dalam Perl. Sayangnya gue gak begitu ngerti Perl, dan gue kurang suka sama bahasanya karena "terlalu dinamis", sehingga membuat code yang ditulis cepat untuk menjadi sulit dibaca.

Gue juga sempat coba pakai Fancyupload yang ditulis oleh Harald Kirschner, sebuah multi file uploader yang bekerja menggunakan Flash. Fancyupload ini gue lihat juga dipakai sama Joomla! CMS. Sayangnya ada 2(dua) kekurangan yang menurut gue cukup penting. Fancyupload ini tidak jalan di mac, dan setiap data yang di upload content-type nya pasti "application/octet-stream", bikin sebel. Biasanya gue kalo periksa file yang di upload, gue pasti periksa berdasarkan extension dan content-type nya, kalo beda biasanya filenya tidak gue terima.

Rasmus sendiri, menurut blog tersebut, langsung menyatakan bahwa dia telah menulis fungsi pendukung tersebut di dalam Alternative PHP Cache, sebuah PHP library yang merupakan bagian dari PHP Extension Community Library (PECL). Contohnya, beserta source code nya pun langsung diberikan. Tapi, menurut gue, sialnya, dia menulis contohnya menggunakan Yahoo! User Interface Framework dan gak pake komentar. Bukannya gue gak suka sama framework. Tapi menurut gue, kurang bijaksana sekali memberikan contoh code menggunakan framework, gak peduli se-straightforward apapun contohnya. Dan untuk sebuah contoh code, menurut gue lagi, komentar itu luar biasa pentingnya untuk mengerti step-by-step apa saja yang terjadi, atau mengapa terjadi, di dalam code tersebut.

Oleh karena itu, gue mau mencoba untuk membuat versi yang lebih sederhana, tanpa framework apapun dan penuh komentar ^^. Dalam kesempatan ini gue mau coba jabarkan dari awal, mulai dari menginstall APC modul itu sendiri, mengkonfigurasi modul tersebut, hingga menggunakannya.


Instalasi dan Konfigurasi APC

Untuk menggunakan fungsi file upload tracker menggunakan APC, kita butuh php 5.2+. Gue sudah mencoba menginstall APC ini diatas Windows dan Debian based Linux. Untuk Windows kita harus mendownload APC library secara manual. PECL zip package yang disediakan oleh php.net tidak mengikutsertakan library APC dalam distribusinya.

Setelah di download php_apc.dll tersebut tinggal dimasukkan ke dalam extension directory yang telah di definisikan di dalam php.ini. Untuk menginstall APC di dalam Debian based Linux gue menggunakan tutorial yang ini. Untuk install di distribusi linux yang lain dan Operating System yang lain silahkan cari di google. Kesuksesan dan kegagalan instalasi biasanya dipengaruhi berbagai macam aspek, yang tidak semuanya gue tahu dan tidak bisa gue jabarkan panjang lebar disini.

Pokoknya setelah kalian berhasil menginstall APC tersebut, maka kita harus mengatur konfigurasinya di dalam php.ini. Yang pertama adalah mendaftarkan library tersebut dalam daftar extension supaya dikenal oleh PHP.

extension=php_apc.dll


Di linux tidak berbeda jauh

extension=apc.so


Setelah ini, kita harus menyalakan fungsi RFC 1867, dan tergantung kalian ingin mencoba file upload dimana, lokal server atau remote server, ada beberapa perbedaan dalam konfigurasinya supaya nanti codenya bisa di test. Gue akan kasih lihat disini konfigurasi lokal server gue yang gue sadur dari IBM yang membahas thema yang sama.

...
post_max_size = 400M
...
upload_max_filesize = 400M
...
[APC]
apc.rfc1867 = on
apc.max_file_size = 200M
...


Mari kita lihat, gue merubah nilai maximum file size diatas 200M, kenapa? Karena apabila kita mengupload file di lokal server, maka file tersebut ter-upload begitu cepatnya, sehingga APC tidak sempat bereaksi untuk menghitung kemajuannya. Oleh karena itu untuk mengetest di lokal server kita butuh file yang cukup besar, biasanya diatas 150M. Oleh karena itu juga, kita butuh merevisi nilai maximum file size di php.ini. Untuk remote server atau produktif server, kita hanya perlu menyalakan fungsi RFC 1867 saja, dalam arti, kita hanya perlu menambahkan "apc.rfc1867 = on" di dalam php.ini kita. Selebihnya bisa dibiarkan sesuai nilai standardnya.

Untuk mengetest apakah semua instalasi dan konfigurasi berjalan dengan baik dan benar, maka setelah restart apache kita harung menengok phpinfo(). Apabila disitu terdapat informasi tentang APC seperti screenshot dibawah, maka apc sudah terinstall dengan benar dan kita bisa mulai menggunakannya.



Kalau kalian ingin tahu lebih lanjut tentang arti dan fungsi dari masing-masing konfigurasi APC silahkan membaca dokumentasinya. Sekarang kita bisa memulai untuk bereksperimen menampilkan informasi proses upload file. Sekedar informasi, semua code yang akan gue tulis, baik itu php, html atau javascript code, berada dalam satu file, yaitu upload_progress.php. Hal ini gue lakukan sebenarnya hanya untuk kemudahan saja dalam mengerti penggunaan APC. Kalau kalian sudah mengerti, silahkan implementasikan dengan cara kalian sendiri-sendiri, dan gunakan Framework apa saja yang kalian suka.


Upload Form

Mari kita bikin upload form yang sederhana saja.

<form action="upload_progress.php" enctype="multipart/form-data" 
      id="upload_form" method="post" 
      onsubmit="postForm('upload_form'); 
      return false;" target="hiddenframe">
<input id="progress_key" name="APC_UPLOAD_PROGRESS" 
       value="<?php echo uniqid()?>" type="hidden">
<input id="test_file" name="test_file" type="file">
<input value="Upload!" type="submit">
</form>
<div id="progress_win">
</div>
<iframe name="hiddenframe" style="display: none;"></iframe>


So, selesai. Sekarang mari lihat satu-satu. di baris pertama untuk form tag, kita punya atribut action yang mengacu pada dirinya sendiri apabila form tersebut di submit. Atribute enctype, karena kita ingin mengupload file, atribut method seperti biasa, post. Kita memiliki atribut Id yang pada atribut onsubmit di berikan sebagai parameter kepada fungsi javascript postForm. Dan kita memiliki atribut target, yang memiliki nilai "hiddenframe". Nilai ini mengacu pada nama iFrame yang didefinisikan di baris 8(delapan).

Dengan menggunakan atribut target pada form tag, maka apabila form tersebut di submit, proses submit tersebut akan dijalankan di Iframe, sehingga halaman dimana form tersebut berada tidak akan di reload. Dengan atribut onsubmit, maka sebelum form tersebut di submit, maka fungsi yang ada di dalam onsubmit tersebut dijalankan. Return false sebenarnya menyatakan bahwa setelah menjalankan fungsi tersebut maka gagalkan operasi submit form. Kenapa digagalkan? nanti gue kasih tahu di bagian javascript.

Baris berikutnya kita punya satu hidden input field. Field ini WAJIB ada apabila kalian ingin menggunakan APC untuk mendeteksi kemajuan upload file. Atribut Id pada input field ini bisa kalian definisikan sesuka kalian, gue definisikan sebagai progress_key. Atribut name harus sesuai dengan konfigurasi APC pada apc.rfc1867_name yang bisa dilihati di phpinfo(). setelah itu kita memiliki atribut value yang gue beri nilai yang unik. Nilai yang unik ini penting untuk orientasi APC ketika memproses kemajuan upload file. Apabila pada waktu bersamaan ada beberapa orang yang mengupload file, katakanlah user A dan B dan kalian memberikan id pada atribut value nya sama, maka APC bisa bingung, 2 progress dari 2 orang berbeda, tapi idnya sama, yang mana punya siapa? ^^

Di baris 6 kita punya div tag. Ini fungsinya sebagai container untuk menampilkan progress bar nya. Disini gue gak akan menjabarkan cara membentuk progress bar, karena untuk itu sudah banyak tutorialnya, gue hanya akan menunjukkan total prosesnya dalam persen. Sekarang mari kita lihat javascriptnya.


Javascript

Karena kita akan bekerja menggunakan AJAX, maka mari kita buat fungsi yang mempersiapkan sebuah instance dari HTTP Request Object, supaya nanti tinggal dipakai. Thema AJAX sendiri gak akan gue bahas panjang lebar. Contoh dan Tutorial bisa lihat di salah satu artikel dalam blog gue atau cari di google.

function createRequestObject()
   var requestObject;
   requestObject = false;
   if( window.ActiveXObject ){
       for( var i = 5; i; i-- ){
           try{
              if( i == 2 ){
               requestObject = 
                     new ActiveXObject( "Microsoft.XMLHTTP" );   
           }else{       
               requestObject =
                     new ActiveXObject( "Msxml2.XMLHTTP." + i + ".0" );
           }
           break;
         }catch( excNotLoadable ){                       
               requestObject = false;
         }
       }
   }else{
       requestObject = new XMLHttpRequest();
   }
   return requestObject;
}

var http = createRequestObject();


So, dengan ini kita sudah mempersiapkan sebuah instance dari HTTP Request Object. Sekarang kita buat fungsi postForm() yang akan dipanggil ketika html form yang barusan kita buat di submit.

function postForm(formName){
 document.getElementById(formName).submit();
 setTimeout('updateProgress()', 100);
}


Isinya mudah saja. HTML form dengan nama yang didefinisikan di submit. setelah itu kita menunggu 100ms sebelum menjalankan fungsi updateProgress(). Kenapa harus menunggu? Karena file yang di upload butuh waktu untuk mencapai server. Apabila kita tidak menunggu, maka APC tidak memiliki informasi apapun untuk dikirimkan kembali ke kita, dalam hal ini APC akan mengirimkan nilai false. Dan itu sangat tidak baik.

Interval 100ms gue gunakan hanya untuk lokal server. Untuk remote server ada baiknya untuk mendefinisikan interval yang lebih besar, satu hingga dua detik (2000ms) karena pengiriman data dari client hingga ke server bisa memakan waktu lama tergantung kecepatan internet.

Sekarang mari kita lihat apa isi di dalam fungsi updateProgress().

function updateProgress(){
 progress_key = document.getElementById('progress_key').value;
 http.open("GET", 'upload_progress.php?progress_key='+progress_key, true);
   http.onreadystatechange = function () {
       if (http.readyState == 4) {
           if (http.status == 200) {
             the_object = eval("(" + http.responseText + ")");           
             if(!the_object.done){
               result = Math.round(
                         (the_object.current/the_object.total) * 100);
               document.getElementById('progress_win').innerHTML = 
                         result +'%';
               setTimeout("updateProgress()",500);
             }else{
               document.getElementById('progress_win').innerHTML = '100%';
             }
           }
       }
   }
 http.send(null);
}


Disini kita lihat bahwa kita mengirimkan GET Request ke server dengan parameter progress_key yang diambil dari input hidden field yang unik tadi. Server nantinya akan mengirimkan response text berupa JSON. Response text tersebut akan dirubah menjadi javascript object dengan eval(). Lalu kita check apakah object atribut "done" didefinisikan dalam object. Apabila tidak, maka hitung kemajuannya dalam persen, lalu tampilkan nilainya dalam div container. Setelah itu tunggu beberapa saat, dalam hal ini gue memasang interval 500ms, dan ulangi proses tersebut.

Server akan menambahkan atribut "done" apabila proses upload sudah selesai. Dan apabila ini terjadi, maka angka persen di div container akan ditulis "100%". Mengenai definisi return array oleh APC silahkan baca manualnya pada bagian RFC1867. Dengan ini javascript kita kelar. Sekarang kita bisa lihat PHP scriptnya.


PHP script

Disini script kita akan meng-handle 2 macam proses, yang pertama adalah upload file itu sendiri, dan yang kedua adalah membaca kemajuan proses upload.

if($_SERVER['REQUEST_METHOD']=='POST') {
  //implement your upload code here
  //e.g. @move_uploaded_file($filename, $destination)
  exit;
} else if(isset($_GET['progress_key'])) {
  $status = apc_fetch(ini_get('apc.rfc1867_prefix').
                         $_GET['progress_key']);
  echo json_encode($status);
  exit;
}else{
  //you can implement some code to display error here
}


Scriptnya mudah saja apabila request method yang diterima adalah post, maka upload filenya. disini kita bisa memasukkan code yang biasa kita implementasikan kalau kita ingin mengupload file.

Apabila request method nya bukan post, maka periksa apakah GET parameter dengan nama "progress_key" di definisikan, jika ya maka ambil informasi tentang status upload file dengan apc_fetch(). Fungsi ini_get() disini adalah untuk mengambil prefix yang didefinisikan di konfigurasi apc (bisa dilihat di phpinfo()). Setiap file yang di upload dan memiliki hidden field "APC_UPLOAD_PROGRESS" pada formnya, APC bisa mengidetentifisikan kembali melalui prefix yang didefinisikan di php.ini dan value yang didefinisikan di hidden field tersebut.

Fungsi apc_fetch() akan mengirimkan array atau boolean false. Apabila dia mengirimkan array, maka kita akan merubah array tersebut menjadi JSON dengan json_encode() function dan mengirimkannya kembali ke client dalam bentuk plain text.

Jadi deh. Tinggal di test. Source code yang kumplit bisa kalian dapatkan disini dan di bawah ini hasilnya, kalian bisa langsung coba ^^.

Happy coding.

Zend PHP 5 Certified Engineer

Friday, June 20, 2008 11:02 PM | 4 comments | 0 backlinks |

Well, from today i am a proud Zend PHP 5 Certified Engineer. It was not easy though, even with the fact that i already worked with PHP for about 5 years ^^. But there was just some question i not familiar with, because i never use it in my daily work with PHP. Difference between PHP 4 and PHP 5 was asked but it is not so difficult to answer. But some of the PHP specific questions is really hard to answer, especially the questions related to stream functions ^^. The New Object Oriented Paradigm and Security issues was for me the easiest one.

I took the Exam in Frankfurt am Main, in a Training Center named Brand EDV Training located in Ostbahnhof area. Well from the outside looks not so promising, the building seems so old and dusty. But well Frankfurt is an old town actually, and this is not the downtown.

As i entered the office, it's looked more and more promising. ^^ Well the reception was very kind. He asked about my ID and asked me to sign some forms about Terms and Condition, Privacy Policy and something like that. He said, i'm not like an Indonesian, more like Chinese. I said, "how can you say that?". And he said, "because my MOTHER COME FROM INDONESIA." Huh? cool, well he looks like an Indonesian to me, but more like East Indonesian, maybe Maluku, Timor or somewhere around there. ^^ Definitely not from Java.

Well after some more chit chat, he brought me into some kind of a class room and prepare the exam for me. I had 90 minutes to finish the exam, and i was finish in about 45 minutes. I took a mock exam a week before, and can answer it in about 30 minutes, but the real exam is actually tougher than that.

Anyway this icon is just nice to put on my blog ^^. What about the ZCE title? Should i put that on my name to? along with the German Dipl. Inf.? Boah, it will be too much show off, will it not?

My Google App Engine Account

Thursday, April 10, 2008 8:07 PM | 1 comments | 0 backlinks |

Google App Engine enables you to build web applications on the same scalable systems that power Google applications. No assembly required. It's easy to scale. AND It's free to get started. How's that sounds, huh? That's the new Google App Engine.

On April 7th, 2008 i read an article on ZDNet.com telling that Google announces App Engine. I thinked: "WOW! this is great news". I really want to try it. Well the problem is the service is being opened up to the first 10,000 developers that request an account. Of course its free, but 10, 000 is not much. But i try to request an account anyway. In fact, at that time Google can not accept account request anymore.

But, Google give an option that, if there is another chance to request an account, you will be informed. And there it is 3 days later, i got an email from google that informed me, i have the opportunity to try one of the newest google service. ^^
Hello,

Thanks for signing up to try Google App Engine! Your account has been activated, so you can begin building applications!

To start creating applications with Google App Engine, simply follow this link (you may need to sign in with your xxxxxx.xxxxxx@gmail.com Google Account):

http://appengine.google.com/

Thanks!
The Google App Engine Team

I can just say YES! At that time. Quick browse the tutorial and download the App Engine for local test. Google did his homework and create a nice video tutorial and Getting Started Guide.

Kevin Gibbs says on Google Campfire One that Python are the first language for Google App. Well I say, I am waiting for PHP to be Next!!

Okay folks!! Just wait my next Masterpiece on Google App Engine ^^.