
- 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.