PHP Closures

Tags: php

PHP Closures

(also posted on https://medium.com/@nuttaponnjyodkaew)

เมื่อช่วงกลางปีที่แล้วเพิ่งมาสังเกตและสงสัยว่าการเขียน route สวยๆของ Laravel เนี่ยเขาทำกันยังไง

Route::get('/', function () {
    return 'Hello World';
});

ก็เลยไปหาอ่านดูจนมาได้รู้จักกับ Closure

Closure หรือเรียกอีกชื่อหนึ่งว่า Anonymous functions คือการประกาศ function ขึ้นมาลอยๆโดยไม่จำเป็นต้องมีชื่อ มีประโยชน์กับงานแนว callback ต่างๆ โดยความสามารถนี้เริ่มมีมาตั้งแต่ PHP 5.3 เช่น

$hello = function($name) {
 echo “Hello ”, $name, “\n”;
};

$hello(“World”); // Hello World
$hello(“วันหยุด”); // Hello วันหยุด

นอกจากนี้ Closure ยังสามารถ inherit variables จากภาย parent scope เข้าไปใช้งานข้างในได้ด้วยการใช้ “use” โดยค่าของ variable ที่เปลี่ยนแปลงภายใน closure จะไม่ส่งผลกับ variable ที่อยู่ด้านนอก

$base_number = 5;
$power_by = function($exponent) use ($base_number) {
 $base_number = pow($base_number, $exponent);
 return $base_number;
};
echo $power_by(2), “\n”; // 25
echo $base_number, “\n”; // 5

ตัวอย่างการใช้งานจริง

เนื่องจากงานที่ทำอยู่ส่วนใหญ่จะเป็นการเขียน worker เพื่อรับส่งงานผ่าน RabbitMQ และจะต้องมีการ process บางอย่างระหว่างทาง โดยเราไม่อยากผูก logic การทำงานซับซ้อนไว้ใน class ใด class หนึ่ง เลยใช้ Closure เพื่อมาประกอบร่างสิ่งต่างๆไว้ด้วยกันใน worker

// สร้างตัวรับงานจาก RabbitMQ
$consumer = new Consumer();

// สร้างตัวส่งงานที่ทำเสร็จแล้วส่งกลับไปที่ RabbitMQ 
$publisher = new Publisher(); 

// สร้างตัวทำงานบางอย่างที่เราต้องการ
$processor = new Processor();

// สร้างตัวเอาข้อมูลลงฐานข้อมูล
$db = new DB();

$callback = function($rabbitmq_message) use ($processor, $db, $publisher) {
    $processed_item = $processor->process_item($rabbitmq_message);
    $db->save($processed_item);
    $publisher->publish($processed_item);
};

// สั่งให้ consumer ต่อ queue server ไว้และทำการเรียก callback
// เพื่อทำงานตามที่เรากำหนด เมื่อได้ message จาก queue
$consumer->listen($callback);

ตัวอย่างด้านบนเป็นแค่ code หยาบๆพอให้เห็นภาพ ไว้โอกาสหน้าจะมาแชร์เรื่อง RabbitMQ ครับ