Null Object Pattern Generator
Creates Null Object pattern infrastructure for eliminating null checks.
When to Use
| Scenario | Example |
|---|---|
| Optional dependencies | Logger, Cache, Notifier |
| Missing entities | Customer, User, Product |
| Feature toggles | Disabled feature returns null object |
| Default implementations | No-op defaults |
Component Characteristics
Interface
- •Defines expected behavior
- •Shared by real and null implementations
- •Enables polymorphic usage
Null Object
- •Implements interface with no-op behavior
- •Returns neutral values
- •Never throws on calls
Benefits
- •Eliminates null checks
- •Follows Liskov Substitution
- •Simplifies client code
Generation Process
Step 1: Generate Interface
Path: src/Domain/{BoundedContext}/
- •
{Name}Interface.php— Interface withisNull()method
Step 2: Generate Null Object
Path: src/Domain/{BoundedContext}/
- •
Null{Name}.php— Null implementation returning neutral values
Step 3: Generate Real Implementation
Path: src/Domain/{BoundedContext}/
- •
{Name}.php— Real implementation with business logic
Step 4: Generate Tests
- •
Null{Name}Test.php— Null object behavior tests
File Placement
| Component | Path |
|---|---|
| Interface | src/Domain/{BoundedContext}/ |
| Null Object | src/Domain/{BoundedContext}/ |
| Real Implementation | src/Domain/{BoundedContext}/ |
| Unit Tests | tests/Unit/Domain/{BoundedContext}/ |
Naming Conventions
| Component | Pattern | Example |
|---|---|---|
| Interface | {Name}Interface | CustomerInterface |
| Real Implementation | {Name} | Customer |
| Null Object | Null{Name} | NullCustomer |
| Test | {ClassName}Test | NullCustomerTest |
Neutral Return Values
| Type | Neutral Value |
|---|---|
string | '' (empty string) |
int | 0 |
float | 0.0 |
bool | false |
array | [] |
void | No return |
| Object | Empty/default instance |
| Collection | Empty collection |
Quick Template Reference
Interface
php
interface {Name}Interface
{
public function {method1}(): {returnType1};
public function {method2}({params}): {returnType2};
public function isNull(): bool;
}
Null Object
php
final readonly class Null{Name} implements {Name}Interface
{
public function {method1}(): {returnType1}
{
return {neutralValue1};
}
public function isNull(): bool
{
return true;
}
}
Real Implementation
php
final readonly class {Name} implements {Name}Interface
{
public function __construct({properties}) {}
public function {method1}(): {returnType1}
{
return {realImplementation};
}
public function isNull(): bool
{
return false;
}
}
Usage Example
Repository Returning Null Object
php
final readonly class DoctrineCustomerRepository implements CustomerRepositoryInterface
{
public function findById(CustomerId $id): CustomerInterface
{
$row = $this->connection->fetchAssociative(
'SELECT * FROM customers WHERE id = :id',
['id' => $id->toString()]
);
if ($row === false) {
return new NullCustomer();
}
return $this->hydrate($row);
}
}
Client Code Without Null Checks
php
final readonly class CreateOrderUseCase
{
public function execute(CreateOrderCommand $command): Order
{
$customer = $this->customers->findById($command->customerId);
// No null check needed - NullCustomer returns 0.0
$discount = $customer->getDiscount();
$order = Order::create(
customerId: $customer->id(),
items: $command->items,
discount: $discount
);
return $order;
}
}
Anti-patterns to Avoid
| Anti-pattern | Problem | Solution |
|---|---|---|
| Throwing in Null | Unexpected exceptions | Return neutral values |
No isNull() | Can't detect null object | Add isNull method |
| Different Interface | LSP violation | Same interface as real |
| Side Effects | Unexpected behavior | Pure no-op methods |
| Complex Logic | Not a null object | Keep simple and neutral |
References
For complete PHP templates and examples, see:
- •
references/templates.md— Interface, NullObject, Real Implementation, NullLogger, NullCache templates - •
references/examples.md— NullCustomer, NullNotifier, Repository integration examples and tests