# Laravel Events และ Listeners ปี 2026: สถาปัตยกรรม Event-Driven และคำถามสัมภาษณ์ > คู่มือฉบับสมบูรณ์เกี่ยวกับ Laravel events และ listeners สำหรับสถาปัตยกรรม event-driven เรียนรู้ observer pattern, queued listeners, event subscribers และคำถามสัมภาษณ์ทางเทคนิค - Published: 2026-08-20 - Updated: 2026-08-20 - Author: Anthony Fillion-Maillet - Tags: laravel, events, listeners, event-driven, observer-pattern, queue - Reading time: 12 min --- Laravel events และ listeners ใช้งาน [observer pattern](https://refactoring.guru/design-patterns/observer) แยก component ออกจากกันโดยให้ส่วนต่างๆ ของแอปพลิเคชันตอบสนองต่อการกระทำโดยไม่ต้องพึ่งพากันโดยตรง เมื่อผู้ใช้สั่งซื้อ event `OrderShipped` จะถูกเรียก และ listener แยกต่างหากจัดการการแจ้งเตือน การวิเคราะห์ และการอัปเดตสินค้าคงคลังอย่างอิสระ > **Laravel 12 Event Discovery** > > Laravel 12 ค้นหา listener ใน `app/Listeners` โดยอัตโนมัติ class ใดๆ ที่มี method `handle` หรือ `__invoke` พร้อม type-hint ไปยัง event class จะถูกลงทะเบียนโดยอัตโนมัติ ไม่ต้องมีไฟล์กำหนดค่า ## วิธีการทำงานของ Event Discovery ใน Laravel 12 ตั้งแต่ Laravel 11 `EventServiceProvider` ถูกลบออก Laravel สแกนไดเรกทอรี `Listeners` และใช้ reflection เพื่อกำหนดว่า event ใดที่ listener แต่ละตัวตอบสนองตาม type hint ใน method signature ของ `handle` ```php // app/Listeners/SendOrderConfirmation.php order->user } } ``` Listener ด้านบนถูกลงทะเบียนโดยอัตโนมัติสำหรับ event `OrderShipped` ไม่ต้อง binding ด้วยตนเองใน service provider สิ่งนี้ลด boilerplate และรักษาความสัมพันธ์ event-listener ให้ใกล้กับโค้ดที่ implement เพื่อตรวจสอบ listener ที่ลงทะเบียน ให้รัน `php artisan event:list` สำหรับ production ให้ cache manifest event ด้วย `php artisan event:cache` เพื่อข้ามการสแกนไดเรกทอรีในแต่ละ request ## การสร้าง Events และ Listeners ด้วย Artisan Laravel มีคำสั่ง Artisan สำหรับสร้าง scaffold events และ listeners: ```bash # สร้าง event class php artisan make:event OrderShipped # สร้าง listener ที่เชื่อมโยงกับ event php artisan make:listener SendShipmentNotification --event=OrderShipped ``` Event class ที่สร้างขึ้นใช้สาม trait: `Dispatchable` สำหรับ method static `dispatch()`, `InteractsWithSockets` สำหรับ broadcasting และ `SerializesModels` สำหรับ serialize Eloquent model เมื่อ listener ถูก queue ```php // app/Events/OrderShipped.php route('orders.index'); } } ``` สำหรับ dispatch แบบมีเงื่อนไข ใช้ `dispatchIf()` หรือ `dispatchUnless()`: ```php // Dispatch เฉพาะเมื่อ order มีหมายเลข tracking OrderShipped::dispatchIf($order->tracking_number !== null, $order); ``` ## Queued Listeners สำหรับการดำเนินการที่ช้า Listener ที่ส่งอีเมล เรียก API ภายนอก หรือทำการคำนวณหนักควรทำงานแบบ asynchronous implement `ShouldQueue` เพื่อผลัก listener ไปยัง queue: ```php // app/Listeners/SendShipmentNotification.php order->user } } ``` ปรับแต่ง connection และชื่อ queue ด้วย property `$connection` และ `$queue` หรือใช้ method runtime: ```php public function viaConnection(): string { return 'redis'; } public function viaQueue(): string { return $this->event->order->priority === 'high' ? 'high-priority' : 'default'; } ``` ### Conditional Queueing ด้วย shouldQueue บางครั้ง listener ควร queue ตามข้อมูล event เท่านั้น: ```php public function shouldQueue(OrderShipped $event): bool { // Queue เฉพาะ order ที่มากกว่า 3,000 บาท return $event->order->total >= 3000; } ``` ## Database Transactions และ Event Timing Queued listener ที่ถูก dispatch ภายใน transaction อาจประมวลผลก่อนที่ transaction จะ commit ทำให้เกิดข้อผิดพลาดข้อมูลหายไป มีสองวิธีแก้ไข: **1. กำหนดค่าทั่วไป** ใน `config/queue.php`: ```php 'connections' => [ 'redis' => [ 'after_commit' => true, ], ], ``` **2. ต่อ listener** ด้วย `ShouldQueueAfterCommit`: ```php use Illuminate\Contracts\Queue\ShouldQueueAfterCommit; class UpdateInventory implements ShouldQueueAfterCommit { public function handle(OrderShipped $event): void { // ปลอดภัยที่จะ query order, transaction ได้ commit แล้ว } } ``` สำหรับ event เอง implement `ShouldDispatchAfterCommit` บน event class: ```php use Illuminate\Contracts\Events\ShouldDispatchAfterCommit; class OrderShipped implements ShouldDispatchAfterCommit { // Event จะ dispatch หลังจาก transaction commit เท่านั้น } ``` ## Unique Listeners เพื่อป้องกันการซ้ำ Interface `ShouldBeUnique` ป้องกัน listener ซ้ำจากการเข้า queue ขณะที่มีตัวหนึ่งกำลังประมวลผล: ```php use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; class ProcessLicenseKey implements ShouldQueue, ShouldBeUnique { public $uniqueFor = 3600; // Lock หมดอายุหลัง 1 ชั่วโมง public function uniqueId(LicensePurchased $event): string { return 'license:' . $event->license->id; } public function handle(LicensePurchased $event): void { // สร้างและกำหนด license key } } ``` หาก license ID เดียวกันเรียก event หลายครั้งอย่างรวดเร็ว เฉพาะ listener ตัวแรกเท่านั้นที่ประมวลผล ความพยายามต่อมาพบว่า lock ถูกถือไว้และข้าม queueing ## Event Subscribers สำหรับ Events ที่เกี่ยวข้อง เมื่อ event หลายตัวที่เกี่ยวข้องใช้ logic การจัดการร่วมกัน event subscriber จัดกลุ่ม handler ในคลาสเดียว: ```php // app/Listeners/UserActivitySubscriber.php 'handleLogin', Logout::class => 'handleLogout', ]; } } ``` Subscriber ปฏิบัติตามกฎ automatic discovery หาก method handler อยู่ใน subscriber class พร้อมพารามิเตอร์ที่ type-hint อย่างถูกต้อง Laravel จะลงทะเบียนโดยอัตโนมัติ ## การฟัง Multiple Events ด้วย Union Types Listener เดียวสามารถตอบสนองต่อ event หลายประเภทโดยใช้ PHP 8 union types: ```php public function handle(OrderShipped|OrderCancelled $event): void { match (true) { $event instanceof OrderShipped => $this->notifyShipped($event), $event instanceof OrderCancelled => $this->notifyCancelled($event), }; } ``` Pattern นี้ทำงานได้ดีสำหรับการแจ้งเตือนที่ปฏิบัติตาม logic ที่คล้ายกันในประเภท event ที่แตกต่างกัน ## การเลื่อน Events ด้วย Event::defer Laravel 12 แนะนำ `Event::defer()` เพื่อเลื่อนการ dispatch event จนกว่า code block จะเสร็จสมบูรณ์ สิ่งนี้รับประกันว่า listener มีสิทธิ์เข้าถึง record ที่เกี่ยวข้องทั้งหมด: ```php use Illuminate\Support\Facades\Event; Event::defer(function () { $user = User::create(['name' => 'John']); $user->posts()->create(['title' => 'Welcome']); }); // Event สำหรับการสร้างทั้ง User และ Post dispatch ที่นี่ ``` หาก exception เกิดขึ้นภายใน closure event ที่เลื่อนจะไม่ถูก dispatch ## คำถามสัมภาษณ์เกี่ยวกับ Laravel Events และ Listeners การสัมภาษณ์ทางเทคนิคมักทดสอบความเข้าใจสถาปัตยกรรม event-driven นี่คือคำถามที่แยกแยะ Laravel developer ที่มีประสบการณ์: **Q: Laravel 12 ลงทะเบียน event listener อย่างไรโดยไม่มี EventServiceProvider?** Laravel สแกน `app/Listeners` โดยใช้ reflection มันอ่าน type hint บน method `handle()` หรือ `__invoke()` เพื่อกำหนดว่า event ใดที่ listener แต่ละตัวตอบสนอง Cache manifest ใน production ด้วย `php artisan event:cache` **Q: เมื่อใดที่ listener ควร implement ShouldQueue?** เมื่อใดก็ตามที่การดำเนินการใช้เวลามากกว่าไม่กี่มิลลิวินาที: ส่งอีเมล เรียก API ภายนอก สร้างรายงาน หรือประมวลผลไฟล์ Listener แบบ synchronous บล็อก HTTP response **Q: ShouldQueueAfterCommit แก้ปัญหาอะไร?** Queued listener อาจประมวลผลก่อนที่ database transaction จะ commit หาก listener query สำหรับ record ที่เพิ่งสร้าง มันจะล้มเหลวเพราะข้อมูลยังไม่ได้ commit `ShouldQueueAfterCommit` เลื่อนการ dispatch queue จนกว่า transaction จะเสร็จสมบูรณ์ **Q: จะป้องกันการประมวลผลซ้ำสำหรับ event เดียวกันได้อย่างไร?** Implement `ShouldBeUnique` กำหนด `uniqueId()` เพื่อส่งคืน cache key ตามข้อมูล event Listener รับ atomic lock และ dispatch ที่ซ้ำจะถูกข้ามหาก lock ถูกถือไว้ **Q: ความแตกต่างระหว่าง event listener และ event subscriber คืออะไร?** Listener จัดการ event ประเภทเดียว Subscriber คือ class ที่ลงทะเบียน handler สำหรับ event ที่เกี่ยวข้องหลายตัวในที่เดียว มีประโยชน์สำหรับการจัดกลุ่ม event การยืนยันตัวตนหรือ audit logging ## ความหมายของ Laravel Events สำหรับแอปพลิเคชันที่ปรับขนาดได้ - Events แยก component ช่วยให้ฟีเจอร์เช่นการแจ้งเตือนและการวิเคราะห์พัฒนาอย่างอิสระ - Queued listener ส่งต่อการดำเนินการที่ช้า รักษา HTTP response ให้เร็ว - `ShouldQueueAfterCommit` ป้องกัน race condition ระหว่าง queue worker และ database transaction - Automatic discovery ใน Laravel 12 ลบ overhead การกำหนดค่า รักษา logic listener ให้ใกล้กับการ implementation - Event subscriber รวมการจัดการ event ที่เกี่ยวข้อง ลดการกระจายไฟล์สำหรับ pattern ทั่วไปเช่นการติดตามกิจกรรมผู้ใช้ - โมดูล `/technologies/laravel/interview-questions/events-listeners` บน [SharpSkill](/technologies/laravel/interview-questions/events-listeners) ครอบคลุม pattern เหล่านี้พร้อมคำถามแบบโต้ตอบ --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/th/blog/laravel/laravel-events-listeners-event-driven-architecture