Higher Order Function di PHP dan Contoh Penerapannya pada array_map

Agung Setiawan 7 November 2016

Higher Order Function di PHP  dan Contoh Penerapannya pada array_map

Akhir-akhir ini saya sedang asik dengan bahasan tentang functional programming. Saat ini kondisi saya adalah masih meraba-meraba tentang apa itu sebenarnya functional programming. Belum ngerti banget tetapi nge-blank sama sekali juga tidak.

Dari pembahasan buku yang saya baca, salah satu faktor sebuah bahasa mendukung functional programming adalah adanya fitur higher order function pada bahasa tersebut.

Apa itu higher order function?

Secara sederhana adalah fungsi yang bisa dijadikan sebagai parameter pada fungsi lain atau fungsi yang dikembalikan dari sebuah fungsi.

Jika kamu familiar dengan Ruby maka kode semacam ini pasti sudah bukan suatu hal yang asing lagi, makanan sehari-hari istilahnya.

[1, 2, 3, 4, 5].map |number|
number * 5
end

Kode di atas akan menghasilkan array baru yang nilai tiap elemennya merupakan hasil kali dirinya sendiri dengan angka 5.

[5, 10, 15, 20, 25]

Semua bisa terjadi karena pada kode di atas kita membuat sebuah block dengan isi number * 5. Block inilah yang membentuk array baru dengan nilai tiap elemen 5 kali lebih besar dari array asalnya.

Block di ruby adalah sebuah fungsi yang dijadikan parameter jika pada bahasa lain. Contohnya map di atas jika pada PHP adalah seperti ini.

$array = [1, 2, 3, 4, 5];
array_map(function($number){
    return $number * 5
}, $array);

Implementasi pada PHP ini jelas terlihat kalau parameter pertama dari fungsi array_map adalah sebuah fungsi.

Kurang lebih seperti itu yang dimaksud higher order function.

Untuk bisa lebih memahami tentang higher order function ini maka kita harus tahu bagaimana array_map dibentuk.

Mengenali Pola

Tanpa menggunakan array_map pun sebenarnya bisa kita mengubah array [1, 2, 3, 4, 5] menjadi [5, 10, 15, 20, 25], yaitu dengan menggunakan perulangan.

Contohnya seperti ini.

$array = [1, 2, 3, 4, 5];
$array = multipleFive($array);
function multipleFive($array){
    $newArray = [];
    foreach($array as $a){
        $newArray[] = $a * 5;
    }
    return $newArray;
}

Contoh lainnya misal kita punya array yang berisi data pelanggan dan ingin mengambil email dari masing-masing pelanggan.

$customers = [
    new Customer("Agung", "com.agungsetiawan@gmail.com"),
    new Customer("Seseorang", "seseorang@gmail.com"),
    new Customer("Yang", "yang@gmail.com"),
    new Customer("Bernama", "bernama@gmail.com"),
    new Customer("Siapapun", "siapapun@gmail.com")
];
$emails = getEmail($customers);
function getEmail($customers){
    $emails = [];
    foreach($customers as $customer){
        $emails[] = $customer->email;
    }
    return $emails;
}

Kode di atas akan menghasilkan array baru yang berisi email dari tiap-tiap customer yang ada di array.

Array
(
[0] => com.agungsetiawan@gmail.com
[1] => seseorang@gmail.com
[2] => yang@gmail.com
[3] => bernama@gmail.com
[4] => siapapun@gmail.com
)

Jika dilihat secara sekilas dari kedua contoh di atas, kode pada bagian looping memiliki bentuk yang berbeda.

function multipleFive($array){
    $newArray = [];
    foreach($array as $a){
        $newArray[] = $a * 5;
    }
    return $newArray;
}

function getEmail($customers){
    $emails = [];
    foreach($customers as $customer){
        $emails[] = $customer->email;
    }
    return $emails;
}

Tetapi kalau kita perhatikan benar-benar, bisa terlihat ada pola yang sama.

Berikut adalah perubahan yang saya lakukan pada kedua looping di atas sehingga pola yang sama bisa dilihat. Yang saya ubah cuma nama variabelnya sehingga tidak mengubah kegunaan fungsi, istilah kerennya refactoring.

function multipleFive($array){
    $temp = [];
    foreach($array as $a){
        $temp[] = $a * 5;
    }
    return $temp;
}

function getEmail($array){
    $temp = [];
    foreach($array as $a){
        $temp[] = $a->email;
    }
    return $temp;
}

Nah kan itu terlihat banget kemiripannya. Sekarang bedanya cuma di bagian inti dari fungsi.

$temp[] = $a * 5;
// vs
$temp[] = $a->email;

Supaya kedua fungsi di atas menjadi semakin mirip, sekarang kita bungkus bagian $a * 5 dan $a->email menjadi fungsi seperti ini.

function multipleFive($array){
    $temp = [];
    $func = function($item){
        return $item * 5;
    }
    foreach($array as $a){
        $temp[] = $func($a);
    }
    return $temp;
}

function getEmail($array){
    $temp = [];
    $func = function($item){
        return $item->email;
    }
    foreach($array as $a){
        $temp[] = $func($a);
    }
    return $temp;
}

Sekarang sudah sama bentuknya $temp[] = $func($a);. Tinggal yang berbeda adalah di bagian definisi $func.

$func = function($item){
    return $item * 5;
}

// vs

$func = function($item){
    return $item->email;
}

Sesuatu yang ada di dalam fungsi supaya nilainya bisa berubah-ubah atau dinamis adalah dijadikan parameter. Akan tetapi, biasanya semua parameter dari sebuah fungsi adalah dalam bentuk nilai, baik itu nilai primitif seperti integer dan string maupun bukan primitif seperti misalnya objek.

Namun kali ini yang kita butuhkan adalah parameter berupa fungsi. Nah di PHP bisakah parameter sebuah fungsi adalah fungsi?

Jawabannya adalah bisa. Di sinilah higher order function memiliki peran yang penting.

function multipleFive($function, $array){
    $temp = [];
    $func = $function;
    foreach($array as $a){
        $temp[] = $func($a);
    }
    return $temp;
}

function getEmail($function, $array){
    $temp = [];
    $func = $function;
    foreach($array as $a){
        $temp[] = $func($a);
    }
    return $temp;
}

Nah kalau udah gini, keduanya 100% mirip ????????

Sekarang cukup gunakan satu fungsi saja yang namanya misal my_map dan bisa kita hilangkan bagian $func = $function menjadi langsung $temp[] = $function.

function my_map($function, $array){
    $temp = [];
    foreach($array as $a){
        $temp[] = $function($a);
    }
    return $temp;
}

Sekarang coba ubah array $customers menjadi array berisi email dari masing-masing pelanggan menggunakan fungsi my_map yang telah kita buat.

$customers = [
    new Customer("Agung", "com.agungsetiawan@gmail.com"),
    new Customer("Seseorang", "seseorang@gmail.com"),
    new Customer("Yang", "yang@gmail.com"),
    new Customer("Bernama", "bernama@gmail.com"),
    new Customer("Siapapun", "siapapun@gmail.com")
];
$emails = my_map(function($item){
    return $item->email;
}, $customers);

Hasilnya akan sama jika kita menggunakan array_map mau pun cara "biasa" menggunakan foreach

Array
(
[0] => com.agungsetiawan@gmail.com
[1] => sesorang@gmail.com
[2] => yang@gmail.com
[3] => bernama@gmail.com
[4] => siapapun@gmail.com
)

Jadi seperti itulah yang dinamakan higher order function. Tiap kali kita menulis kode yang memiliki bentuk yang sama tetapi memiliki perbedaan pada statement maka itu adalah kesempatan bagi kita untuk melakukan refactoring dengan membuatnya menjadi satu fungsi dengan menerima parameter berupa fungsi.

Happy Coding!