The Goodness of Parameter Objects

Sometimes in your code, you'll notice a pattern in which a group of parameters are tend to be passed together. Multiple methods will use the same group of parameters, because one will make no sense without the others. These methods can be either in one class or in several classes.

For instance, you may have a method in a class that filters all projects that were completed between two dates.

class ProjectsRepo
{
    function filterByDate($userId, $startDate, $endDate)
    {
        // return all projects done by user with id = $userId
        // between $startDate and $endDate
    }
}

In another class, you may have another method that uses the same two parameters: $startDate and $endDate to calculate the income earned between these dates.

class Income
{
    function calculateBetweenDates($userId, $startDate, $endDate)
    {
        // calculate the income earned between $startDate and $endDate
    }
}   

Although this seems fine, there's still room for improvement.

Introducing a parameter object

Whenever you have a situation that is similar to the above one, consider refactoring your code by introducing a Parameter Object.

Parameter Object is an object that holds a group of parameters that are usually passed together.

We can refactor the above example by creating a new object called, for example, DateRange and put both $startDate and $endDate in it as properties.

class DateRange
{
    private $start;
    private $end;

    function __construct(DateTime $start, DateTime $end)
    {
        $this->start = $start;
        $this->end = $end;
    }

    public function getStart()
    {
        return $this->start;
    }

    public function getStart()
    {
        return $this->end;
    }
}

Now, instead of passing the $startDate and $endDate individually, we pass the whole DateRange object.

So the ProjectsRepo and Income classes will be changed to something like this:

class ProjectsRepo
{
    function filterByDate($userId, DateRange $range)
    {
        // ...
    }
}

class Income
{
    function calculateBetweenDates($userId, DateRange $range)
    {
        // ...
    }
}   

This change will also be applied to other classes that need the same set of parameters.

What's so good about that?

This refactoring has more benefits than you initially think. First, it's considered a solution for reducing the size of the parameter lists. Long parameter lists are considered much harder to understand and to use than the small ones.

But the real benefit of doing this refactoring is that you might find some behaviors that are more related to the newly created object. Putting those behaviors into a single place, helps you dry your code (remove duplicated code). Which, ultimately, makes it easier do modifications, and test your code.

A good example would be to add a method called includes($date) to check if a certain date falls between the two dates defined in the object ($startDate and $endDate).

So the DateRange class will have this method.

class DateRange
{
    // ...

    public function includes(DateTime $date)
    {
        // Check to see if the given date falls
        // between startDate and endDate
    }
}

Conclusion

Although this isn't the only refactoring to reduce the parameter lists size, it's still considered the best — especially for having a perfect place for moving related behaviors.

So the next time you find yourself passing the same group of parameters, consider introducing a parameter object.

OOP Refactoring PHP
Taha Shashtari

About Taha Shashtari

I'm a freelance web developer. Laravel & VueJS are my main tools these days and I love building stuff using them. I write constantly on this blog to share my knowledge and thoughts on things related to web development... Let's be friends on twitter.