Command Pattern
The Command Pattern is a behavioral design pattern that turns a request, action, or operation into an object. Instead of executing an operation directly, the application creates a command object that contains all the information needed to perform that operation.
This pattern is useful when software needs to queue actions, delay execution, log operations, support undo and redo, organize user actions, or separate the object that requests an operation from the object that performs it.
Introduction
In previous articles of this Design Patterns series, we discussed behavioral patterns such as Strategy Pattern and Observer Pattern. Strategy Pattern helps switch between different algorithms or behaviors. Observer Pattern allows multiple listeners to react when an event happens.
The Command Pattern solves a different problem. It focuses on representing an action as an object. This means an action can be stored, passed around, queued, logged, retried, or executed later.
In real software projects, commands are common in background jobs, task queues, CLI commands, button actions, transaction systems, undo and redo features, workflow engines, and application use cases.
What Is the Command Pattern?
The Command Pattern is a design pattern that encapsulates a request as an object. This object usually contains a method such as execute, handle, or run. When the method is called, the command performs the requested action.
In simple terms, a command object answers the question: what action should be performed?
For example, instead of directly calling an email service from many places in the application, developers can create a SendWelcomeEmailCommand. This command contains the user data and knows how to send the welcome email when executed.
Main Idea of the Command Pattern
The main idea of the Command Pattern is to separate the request for an action from the execution of that action. The object that creates or triggers the command does not need to know every detail about how the action is performed.
The pattern usually includes:
Command interface: Defines a common method such as execute.
Concrete command: Implements the action.
Receiver: The object that performs the real work.
Invoker: The object that triggers the command.
Client: The code that creates and configures the command.
This structure makes actions more flexible and easier to organize.
Why the Command Pattern Is Important
The Command Pattern is important because it gives operations their own structure. When actions are represented as objects, they become easier to store, execute later, retry, log, or combine with other actions.
Without the Command Pattern, application logic may directly call many services in many places. This creates tight coupling and makes it harder to control execution flow.
With Command Pattern, actions become independent objects. The application can decide when and how to execute them.
Problem Without Command Pattern
Imagine an application that sends emails, creates invoices, updates stock, and logs actions directly inside a controller or service:
class OrderController
{
public function placeOrder(Request $request)
{
$order = $this->orderService->create($request->all());
$this->paymentService->charge($order);
$this->inventoryService->decreaseStock($order);
$this->invoiceService->createInvoice($order);
$this->emailService->sendConfirmation($order);
return $order;
}
}This code works, but the controller now coordinates many actions directly. If some actions need to be queued, retried, logged, or undone later, the design becomes harder to manage.
The Command Pattern can move each action into a separate command object.
Basic Command Pattern Example in PHP
First, define a command interface:
interface Command
{
public function execute(): void;
}Now create a receiver class that performs the real work:
class EmailService
{
public function send(string $email, string $message): void
{
// Send email logic
echo 'Email sent to ' . $email;
}
}Then create a concrete command:
class SendEmailCommand implements Command
{
public function __construct(
private EmailService $emailService,
private string $email,
private string $message
) {
}
public function execute(): void
{
$this->emailService->send($this->email, $this->message);
}
}The SendEmailCommand object contains everything needed to perform the email sending action.
Using the Command
The command can be created and executed like this:
$emailService = new EmailService();
$command = new SendEmailCommand(
$emailService,
'user@example.com',
'Welcome to our platform.'
);
$command->execute();The code that executes the command does not need to know the internal details of the email service. It only calls execute.
Command Pattern with an Invoker
An invoker is an object that receives a command and triggers it. The invoker does not know the details of the command. It only knows that the command can be executed.
class CommandInvoker
{
public function run(Command $command): void
{
$command->execute();
}
}
$invoker = new CommandInvoker();
$invoker->run($command);This structure makes it possible to execute different commands through the same invoker.
Real-World Example: Order Commands
Order processing often includes multiple actions. Each action can be represented as a command.
class ChargePaymentCommand implements Command
{
public function __construct(
private PaymentService $paymentService,
private Order $order
) {
}
public function execute(): void
{
$this->paymentService->charge($this->order);
}
}
class CreateInvoiceCommand implements Command
{
public function __construct(
private InvoiceService $invoiceService,
private Order $order
) {
}
public function execute(): void
{
$this->invoiceService->create($this->order);
}
}
class SendOrderConfirmationCommand implements Command
{
public function __construct(
private EmailService $emailService,
private Order $order
) {
}
public function execute(): void
{
$this->emailService->send(
$this->order->customerEmail,
'Your order has been confirmed.'
);
}
}Each command has one responsibility. This makes the order workflow easier to organize and test.
Command Queue Example
One powerful use of Command Pattern is command queues. Commands can be stored in a list and executed later.
class CommandQueue
{
private array $commands = [];
public function add(Command $command): void
{
$this->commands[] = $command;
}
public function run(): void
{
foreach ($this->commands as $command) {
$command->execute();
}
}
}The application can add commands to the queue:
$queue = new CommandQueue();
$queue->add(new ChargePaymentCommand($paymentService, $order));
$queue->add(new CreateInvoiceCommand($invoiceService, $order));
$queue->add(new SendOrderConfirmationCommand($emailService, $order));
$queue->run();This allows actions to be organized and executed in a controlled order.
Command Pattern and Background Jobs
Background jobs are a practical form of the Command Pattern. A job object usually represents an action that should be executed later by a queue worker.
For example, sending an email, generating a PDF, processing an uploaded file, or calling an external API can be placed inside a job command.
This keeps the main request fast. Instead of doing everything immediately, the application dispatches a command or job to a queue.
Command Pattern in Laravel
Laravel uses command-like structures in several places. Laravel jobs, console commands, queued listeners, and action classes are all related to the idea of representing work as an executable object.
A Laravel job may look like this:
class SendWelcomeEmailJob implements ShouldQueue
{
public function __construct(
public User $user
) {
}
public function handle(EmailService $emailService): void
{
$emailService->send(
$this->user->email,
'Welcome to our platform.'
);
}
}This job represents an action that can be queued and executed later. The handle method is similar to execute in the classic Command Pattern.
Laravel Console Commands
Laravel console commands are also command-like objects. They represent actions that can be executed from the command line.
class GenerateReportsCommand extends Command
{
protected $signature = 'reports:generate';
public function handle(): int
{
// Generate reports
return self::SUCCESS;
}
}The command object contains the logic for one specific CLI operation. This keeps command-line tasks organized and reusable.
Command Pattern in Symfony
Symfony also uses command objects for console commands. Symfony Console commands are classes that represent executable CLI tasks.
Symfony Messenger is another strong example. Messages and handlers can represent commands that are dispatched and processed synchronously or asynchronously.
This shows how the Command Pattern appears naturally in modern PHP frameworks.
Command Pattern and Undo Operations
Another classic use case for Command Pattern is undo and redo. If each action is represented as a command object, the application can store executed commands and reverse them later.
To support undo, commands can define an undo method:
interface UndoableCommand
{
public function execute(): void;
public function undo(): void;
}For example, a text editor can represent actions such as typing text, deleting text, or formatting text as commands. Each command can know how to undo its own action.
Undo Example in PHP
class TextEditor
{
public string $content = '';
}
class AddTextCommand implements UndoableCommand
{
public function __construct(
private TextEditor $editor,
private string $text
) {
}
public function execute(): void
{
$this->editor->content .= $this->text;
}
public function undo(): void
{
$this->editor->content = substr(
$this->editor->content,
0,
-strlen($this->text)
);
}
}The command adds text when executed and removes the same text when undone.
Command History Example
A command history can store executed commands for undo support:
class CommandHistory
{
private array $history = [];
public function execute(UndoableCommand $command): void
{
$command->execute();
$this->history[] = $command;
}
public function undoLast(): void
{
$command = array_pop($this->history);
if ($command) {
$command->undo();
}
}
}This approach is useful in editors, design tools, workflow systems, and applications that need reversible actions.
Command Pattern and Logging
Because commands are objects, they can be logged before or after execution. This is useful in systems that need audit logs or operation tracking.
For example, an admin action such as DeleteUserCommand can be logged before it is executed. The system can record who executed the command, when it happened, and what data was involved.
This makes Command Pattern useful for enterprise applications, admin panels, financial systems, and security-sensitive workflows.
Command Pattern and Retry Logic
Commands can also support retry logic. If an action fails because of a temporary error, such as an API timeout, the command can be retried later.
This is common in queue systems. A job command may fail and then be retried automatically based on queue configuration.
Command Pattern makes this easier because each action is isolated inside its own object.
Command Pattern and Transactions
Some commands perform important operations that should be wrapped in database transactions. For example, CreateOrderCommand may create an order, reduce stock, and record payment data.
A command handler or service can execute the command inside a transaction to ensure data consistency.
class TransactionalCommandBus
{
public function __construct(
private DatabaseConnection $database
) {
}
public function dispatch(Command $command): void
{
$this->database->transaction(function () use ($command) {
$command->execute();
});
}
}This allows commands to be executed safely when several database changes must succeed or fail together.
Command Bus
A command bus is an object responsible for dispatching command objects to the correct command handler. It is common in clean architecture, CQRS, and enterprise applications.
Instead of calling handlers directly, the application dispatches a command to the command bus. The command bus finds the correct handler and executes it.
This approach can centralize middleware such as validation, authorization, logging, transactions, and retries.
Command and Handler Example
Some applications separate the command data from the command handler. The command stores data, and the handler performs the action.
class RegisterUserCommand
{
public function __construct(
public string $name,
public string $email,
public string $password
) {
}
}
class RegisterUserHandler
{
public function __construct(
private UserRepositoryInterface $users,
private PasswordHasher $passwordHasher
) {
}
public function handle(RegisterUserCommand $command): User
{
return $this->users->create([
'name' => $command->name,
'email' => $command->email,
'password' => $this->passwordHasher->hash($command->password),
]);
}
}This style is common in application services and CQRS-based designs.
Command Pattern and CQRS
CQRS stands for Command Query Responsibility Segregation. It separates commands, which change state, from queries, which read data.
In CQRS, commands represent operations such as RegisterUser, PlaceOrder, CancelSubscription, or UpdateProfile. Queries represent read operations such as GetUserProfile or ListOrders.
The Command Pattern fits naturally with CQRS because commands are explicit objects representing state-changing actions.
Command Pattern vs Observer Pattern
Command Pattern and Observer Pattern are both behavioral patterns, but they solve different problems.
The Command Pattern represents an action as an object. It is useful for queuing, logging, retrying, undoing, or executing actions later.
The Observer Pattern notifies multiple observers when an event happens. It is useful when several independent reactions should happen after one event.
In short, Command represents a request to do something, while Observer reacts to something that already happened.
Command Pattern vs Strategy Pattern
Strategy Pattern defines interchangeable algorithms or behaviors. The application chooses one strategy to perform a task in a specific way.
Command Pattern encapsulates an action or request as an object. The command may be stored, queued, executed, undone, or retried.
For example, PaymentStrategy chooses how payment is processed. ChargePaymentCommand represents the action of charging a payment.
In short, Strategy is about choosing behavior, while Command is about representing an action.
Command Pattern vs Template Method Pattern
Template Method Pattern defines the skeleton of an algorithm in a parent class and lets child classes customize some steps. It uses inheritance.
Command Pattern encapsulates a complete action as an object and usually uses composition. It is more focused on execution control than algorithm structure.
Use Template Method when the steps of an algorithm are fixed. Use Command when actions need to be stored, executed later, logged, queued, or undone.
Benefits of Command Pattern
The Command Pattern provides many benefits in object-oriented software design.
Main benefits include:
Encapsulates actions as objects.
Separates request creation from request execution.
Supports queues and delayed execution.
Makes undo and redo easier to implement.
Improves logging and auditing of operations.
Supports retry logic for failed tasks.
Keeps actions focused and testable.
Works well with command buses, jobs, and background workers.
These benefits make Command Pattern useful in many real-world applications.
Drawbacks of Command Pattern
The Command Pattern can also have drawbacks. It may increase the number of classes because every action may need its own command class.
For simple operations, this extra structure may be unnecessary. If an action is used only once and does not need queuing, logging, undo, or delayed execution, a direct method call may be clearer.
Another drawback is that command-based systems can become harder to trace if commands and handlers are not organized well.
When to Use Command Pattern
Use the Command Pattern when actions need to be treated as objects or when execution needs more control.
Command Pattern is useful when:
You need to queue tasks for later execution.
You need undo and redo functionality.
You need to log or audit actions.
You need retry logic for failed operations.
You want to separate action request from execution.
You are building CLI commands, jobs, or workflow actions.
You want to organize application use cases clearly.
If these conditions exist, Command Pattern can make the design cleaner and more flexible.
When Not to Use Command Pattern
Do not use Command Pattern when the operation is very simple and does not need to be stored, queued, logged, retried, or undone.
Avoid Command Pattern when:
A direct method call is simpler and clearer.
The action is not reused or delayed.
The pattern adds many classes without real benefit.
The project is small and does not need command architecture.
The command object only wraps one simple line of code.
Design patterns should solve real problems. If Command Pattern only adds complexity, it should be avoided.
Common Mistakes with Command Pattern
One common mistake is creating commands for every small method call. This can make the project overly complex.
Another mistake is putting too many responsibilities inside one command. A command should represent one clear action.
A third mistake is mixing command data and too many infrastructure details in the same class. In larger systems, separating command data from command handlers can improve clarity.
A fourth mistake is not handling failures properly in queued commands. Commands that depend on external APIs should consider retries, timeouts, and error handling.
Best Practices for Command Pattern
To use the Command Pattern effectively, developers should keep commands focused and meaningful.
Useful best practices include:
Use clear names such as RegisterUserCommand or SendInvoiceCommand.
Keep each command focused on one action.
Use command handlers for complex application logic.
Use queues for slow or delayed commands.
Add logging and retry logic where needed.
Use transactions for commands that change multiple records.
Avoid command classes for very simple operations.
Organize commands by domain or feature.
These practices help keep command-based systems clean and maintainable.
Practical Checklist Before Using Command Pattern
Before using the Command Pattern, developers can ask these questions:
Does this action need to be executed later?
Does it need to be queued or retried?
Does it need logging or auditing?
Does it need undo or redo support?
Will representing the action as an object improve clarity?
Is the action important enough to have its own class?
Will this reduce coupling between request and execution?
If the answer is yes to several of these questions, Command Pattern may be a good design choice.
Conclusion
The Command Pattern is a behavioral design pattern that turns actions or requests into objects. It helps organize operations, separate request creation from execution, and support advanced features such as queues, undo and redo, logging, auditing, retries, transactions, and command buses.
Command Pattern is useful in PHP applications, Laravel jobs, Symfony commands, background workers, CLI tools, CQRS systems, workflow engines, and applications that need controlled action execution.
However, Command Pattern should be used carefully. It can add too many classes if applied to simple operations. When used for meaningful actions, it is a powerful tool for building clean, organized, and maintainable object-oriented software.

