PHP
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Object-Oriented PHP
-
Section 5: Working with Data
-
Section 6: Modern PHP (PHP 8)
-
Section 7: Working with Files and Networking
-
Section 8: Common PHP Frameworks Overview
-
Section 9: Tooling and Ecosystem
-
Section 10: Practical Projects
-
Section 11: Interview Practice
-
Section 12: More Standard Library
-
Section 13: Data Structures and Algorithms in PHP
-
Section 14: More Practice Exercises
-
Section 15: More Security and Best Practices
-
Section 16: More Testing and Tooling
-
Section 17: WordPress-Style CMS Concepts
-
Section 18: Advanced OOP Practice
-
Section 19: More Web Fundamentals
-
Section 20: Database Practice
-
Section 21: PHP Manual: Array Functions
-
Section 22: PHP Manual: Date and Calendar Functions
-
Section 23: PHP Manual: Filesystem and Directory Functions
-
Section 24: PHP Manual: Filter and Var Handling
-
Section 25: PHP Manual: Math Functions
-
Section 26: PHP Manual: JSON and XML
-
Section 27: PHP Manual: Network and Stream Functions
-
Section 28: PHP Manual: Error and Exception Handling
-
Section 29: PHP Manual: Output Control and Misc
-
Section 30: PHP Manual: FTP, Zip, and Mail
-
Section 31: Modern PHP Frameworks Deep Dive
-
Section 32: PHP Design Patterns
-
Section 33: More Practice Exercises
-
Section 34: PHP Performance and Deployment
-
Section 35: More Interview Practice
-
Section 36: More PHP Standard Library
-
Section 37: PHP Concurrency and Async
-
Section 38: More Web Development Practice
-
Section 39: PHP Testing Deep Dive
-
Section 40: Composer and Package Development
-
Section 41: PHP Security Deep Dive
-
Section 42: More Practical Projects
-
Section 43: Legacy PHP Maintenance
-
Section 44: More Algorithm Practice
-
Section 45: Final Practice and Review
-
Section 46: PHP for E-Commerce Patterns
-
Section 47: PHP API Design Deep Dive
-
Section 48: PHP Caching Strategies
-
Section 49: PHP Queue and Background Jobs
-
Section 50: PHP Multi-Tenancy Patterns
-
Section 51: PHP Real-Time Features
-
Section 52: PHP CMS and Content Modeling
-
Section 53: PHP Internationalization
-
Section 54: More Framework-Specific Practice
-
Section 55: PHP Legacy Code Refactoring
-
Section 56: More Practice Projects Round 2
-
Section 57: PHP Command-Line Applications
-
Section 58: PHP and Microservices
-
Section 59: More Interview and Review Round 2
242: Service Communication Patterns in PHP Microservices
I want to show you a piece of code that looks perfectly fine during a code review, but will absolutely tank your production environment the moment you hit a certain scale. This is a classic "distributed monolith" mistake.
// In CheckoutService.php
public function completeOrder(Order $order)
{
// 1. Mark order as paid
$this->orderRepo->markAsPaid($order);
// 2. Tell Inventory Service to reserve items (Synchronous HTTP)
$inventoryResponse = $this->httpClient->post('http://inventory-service/reserve', [
'json' => ['order_id' => $order->getId()]
]);
// 3. Tell Shipping Service to create a label (Synchronous HTTP)
$shippingResponse = $this->httpClient->post('http://shipping-service/label', [
'json' => ['order_id' => $order->getId()]
]);
// 4. Send a confirmation email via Notification Service (Synchronous HTTP)
$this->httpClient->post('http://notification-service/send', [
'json' => ['email' => $order->getUserEmail(), 'template' => 'order_confirmed']
]);
return new OrderResponse('Order processed successfully!');
}
The Cascading Failure Trap
At first glance, this is logical. You're coordinating three different services. But here is the reality: you've just created a synchronous chain of dependencies. If the notification-service has a network hiccup or takes 5 seconds to respond, your CheckoutService is blocked. The PHP-FPM worker is sitting there, idling, holding a connection open, and waiting.
If the shipping service slows down and the notification service hangs, your entire checkout process grinds to a halt. This is called a cascading failure. Your users aren't seeing an "Order Confirmed" page; they're seeing a 504 Gateway Timeout because the request timed out at the Nginx level while PHP was still waiting on a distant API call. I've spent way too many weekends debugging these "ghost" outages that only happen during high-traffic sales.
Moving to Asynchronous Event-Driven Communication
The fix isn't to just "increase the timeout." The fix is to ask yourself: "Does the user actually need to wait for this to finish before they get a success message?"
The user needs to know the order was placed. They do not need to wait for the shipping label to be generated or the email to be sent. We should only keep the absolutely critical operations synchronous (like inventory reservation) and move everything else to an asynchronous pattern using a message broker (like RabbitMQ, Redis, or Amazon SQS).
// In CheckoutService.php (The Refactored Version)
public function completeOrder(Order $order)
{
$this->orderRepo->markAsPaid($order);
// CRITICAL: We keep this sync because we can't sell what we don't have.
// If this fails, we want to tell the user immediately.
$this->inventoryService->reserveItems($order);
// NON-CRITICAL: Fire and forget.
// We push a message to a queue and let a background worker handle it.
$this->messageBus->dispatch(new OrderPlacedEvent($order->getId()));
return new OrderResponse('Order processed successfully!');
}
Now, the ShippingService and NotificationService are no longer called directly by the Checkout process. Instead, they are "subscribers" to the OrderPlacedEvent. They pick up the message from the queue and process it at their own pace. If the email service goes down for ten minutes, the messages just sit in the queue. Once it comes back online, it processes the backlog. The user never knows there was a problem; their checkout was instant.
Choosing Between Request-Response and Pub/Sub
You can't move everything to a queue, though. You need to choose your pattern based on the requirement:
- Request-Response (Synchronous): Use this when you need an immediate answer to proceed. Example: Validating a credit card or checking stock levels. Use a circuit breaker pattern here so that if the remote service is down, you fail fast rather than hanging.
- Publish/Subscribe (Asynchronous): Use this for side effects. Example: Sending emails, updating search indexes, or notifying a warehouse. This decouples your services and makes your system significantly more resilient.
A good rule of thumb I use: if the operation is a "side effect" of the main action, it belongs in a queue.
📋 Practical Task
Implement a Decoupled Order Notification System
You have a legacy OrderController that currently calls a SmsNotificationService via a synchronous HTTP call, causing the checkout process to lag whenever the SMS gateway is slow. Your task is to refactor this into an asynchronous pattern.
Requirements:
- Create an
OrderPlacedEventclass that holds theorderId. - Modify the
OrderControllerto remove the direct$this->smsService->send(...)call and instead dispatch theOrderPlacedEventto a mockMessageBus. - Implement an
OrderNotificationHandlerthat "listens" for theOrderPlacedEventand handles the actual SMS sending logic. - Ensure that the
OrderControllerreturns a response to the user immediately after dispatching the event, without waiting for the SMS to be sent.
There are no comments for now.