- A parameter object replaces one or more parameters to a method with a single object instance.
- A result object is a object created specifically for a return value from a method.
Parameter Objects
Changing a method to accept a parameter object is a common refactoring for grouping parameters that belong together.
Unfortunately that’s not the whole story. The real benefit of a parameter object is that it can protect its own invariants, like any other value object.
Take the common date range example. A start and end date belong together, but would it make sense for a start date to come after an end date? Not at all. A parameter object can make sure that never happens.
<?php final class StartDateBeforeEndDate extends \InvalidArgumentException {} class DateRange { private $start; private $end; public function __construct(\DateTimeInterface $start, \DateTimeInterface $end) { $diff = $start->diff($end); if ($diff->invert) { throw new StartDateBeforeEndDate(); } $this->start = $start; $this->end = $end; } // getters, etc }
This sort of checking can shift the responsibility for argument validation out of the objects and methods themselves and into a common value object. For an interface with multiple implementations that lifting of validation to a common, logical place is a huge benefit.
The above has nothing to do with grouping multiple parameters. That’s still a valid reason to use a parameter object, but a parameter object that protects its invariants is useful with just a single property.
Result Objects
As mentioned above, a result object is just something that gets returned from a method. These come with the same benefits as other value objects: real types instead of dynamic mappings and protection of invariants.
A result object means thats its impossible for a class to return an invalid value — the object would prevent that from happening. This may not seem like a big deal, but with multiple implementations of an interface it helps. No question about adherence to the interface because the result object takes care of that.
For example, a method that calculates revenue of something. Revenue can probably not be negative (profit can be). Wrap that rule up in an object.
<?php interface RevenueCalculator { public function calculateRevenue() : Revenue; } final class RevenueLessThanZero extends \InvalidArgumentException {} final class Revenue { /** * int because monetary values as a floating point * is a bad idea. Could even use a `Money` value * object here. * @var int */ private $value; public function __construct(int $revenue) { if ($revenue < 0) { throw new RevenueLessThanZero(); } $this->value = $revenue; } // getters, etc. }
Now anything that that implements RevenueCalculator
cannot return an invalid value. Its clients need not worry or check things themselves.
Also note the use of non-generic exceptions.
Use More Value Objects
In general, value objects are a good thing. Parameter and result objects are just two flavors.
In PHP, any place that a free form array is being used a value object could be put in its place.