Designing Domain Exceptions for PHP Services shows how to apply a focused PHP technique using understandable, runnable examples and clearly defined constraints.
What Problem Does This Solve?
Model domain invariants in constructors and methods; separate expected validation failures from infrastructure errors and avoid hiding exceptions.
Core Concepts
- Identify the data entering the operation and the expected output.
- Model domain invariants in constructors and methods; separate expected validation failures from infrastructure errors and avoid hiding exceptions.
- Handle expected failures and test boundary conditions rather than assuming success.
Example 1: A Small Working Example
Start with a small input so the behavior is easy to follow.
<?php
class DomainExceptionBase extends RuntimeException {}
class InvalidOrderState extends DomainExceptionBase {}
try { throw new InvalidOrderState("Order was already shipped"); } catch (InvalidOrderState $exception) { echo $exception->getMessage(); }
The example isolates the important operation and its expected input. Adapt the values, error handling and boundaries for your application rather than assuming all input is trusted.
Example 2: A Different Case
The second example changes the task or data while using the same general technique.
<?php
function validateQuantity(int $quantity): void { if ($quantity <= 0) { throw new DomainException("Quantity must be positive"); } }
try { validateQuantity(0); } catch (DomainException $exception) { echo $exception->getMessage(); }
The example isolates the important operation and its expected input. Adapt the values, error handling and boundaries for your application rather than assuming all input is trusted.
Practical Example
This practical example is a complete standalone PHP snippet to adapt to a real application.
<?php
function validateQuantity(int $quantity): void { if ($quantity <= 0) { throw new DomainException("Quantity must be positive"); } }
try { validateQuantity(0); } catch (DomainException $exception) { echo $exception->getMessage(); }
// Inspect the next distinct state after the operation.
echo "\nSecond scenario complete";
The example isolates the important operation and its expected input. Adapt the values, error handling and boundaries for your application rather than assuming all input is trusted.
Important Behavior and Edge Cases
- Validate XML size and disable untrusted external resource loading. XMLReader is forward-only; DOM materializes a tree and can consume much more memory.
- Model domain invariants in constructors and methods; separate expected validation failures from infrastructure errors and avoid hiding exceptions.
- Test a malformed input, a missing dependency and a boundary value when those cases apply.
Comparison With Related Approaches
| Approach | Trade-off |
|---|---|
| Designing Domain Exceptions for Services | Model domain invariants in constructors and methods; separate expected validation failures from infrastructure errors and avoid hiding exceptions. |
| Related PHP approach | Immutable value objects protect validated state; mutable arrays are more flexible but cannot enforce invariants automatically. |
Common Beginner Mistakes
| Mistake | Correct Approach |
|---|---|
| Skipping a relevant boundary or security check | Validate XML size and disable untrusted external resource loading. XMLReader is forward-only; DOM materializes a tree and can consume much more memory. |
| Choosing a technique without considering its trade-off | Immutable value objects protect validated state; mutable arrays are more flexible but cannot enforce invariants automatically. |
| Assuming sample data behaves like production input | Test missing fields, unexpected types, failures and the application’s actual trust boundaries. |
Key Takeaways
- Model domain invariants in constructors and methods; separate expected validation failures from infrastructure errors and avoid hiding exceptions.
- Immutable value objects protect validated state; mutable arrays are more flexible but cannot enforce invariants automatically.
- Write tests around the inputs and failure cases most likely in your application.
Use these examples as a starting point and adapt the validations and boundaries to the specific application.