Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Practical PHP Refactoring: Remove Parameter

DZone's Guide to

Practical PHP Refactoring: Remove Parameter

· Agile Zone
Free Resource

Learn more about how DevOps teams must adopt a more agile development process, working in parallel instead of waiting on other teams to finish their components or for resources to become available, brought to you in partnership with CA Technologies.

As Kent Beck says, all refactoring techniques are bidirectional; in the case of add and remove refactorings, one direction increases the moving parts to face with complexity while the other simplifies the design after some responsibilities have been clarified or eliminated.

Why removing a parameter?

Of course, you shouldn't remove a parameter if you're using it. When it is out of place, you should first arrive at a situation where it is no longer referenced inside a method: this refactoring is about its subsequent removal and its possible pitfalls.

Once a parameter is not used anymore, deleting it means you'll have less complexity to worry about: method calls will be easier to perform; they will be easier to understand when read by your colleagues; and debugging or modifying the method body will be easier without adding to your mental load another variable to keep track of.

In case you're struggling with long parameter lists when no one of them can be easily removed, there are other refactorings we will encounter thay may help you consolidate the list in fewer objects.

Steps

Fowler's steps target a static language, so I will tune them to PHP's situation.

  1. Check polymorphic implementations, such as superclasses and subclasses. The method should be modified in every place where it is overridden or derived from.
  2. Following a PHP/JavaScript style, you can start by removing the parameter from the signature. The calls will still work, but the parameter will be ignored.
  3. Afterwards, you can edit calls by removing the actual parameters.

The tests suite should of course be green at the end of the refactoring.

Example

We start from the previous scenario, where we had just added an explicit parameter representing the data of the new invoice to insert. The requirement for progressive numbers was that invoices are maintained in chronological order.

<?php
class RemoveParameter extends PHPUnit_Framework_TestCase
{
    public function testProvidesNextInvoiceNumbersForTheCurrentDate()
    {
        $invoices = new Invoices(array(1 => '2011-10-01', 2 => '2011-11-01'));
        $this->assertEquals(3, $invoices->getProgressiveNumberForInsertion('2011-11-02'));
    }

    public function testNextInvoiceNumberIsAnExistingOneInCaseWeHaveToRenumerate()
    {
        $invoices = new Invoices(array(1 => '2011-10-01', 2 => '2011-11-10'));
        $this->assertEquals(2, $invoices->getProgressiveNumberForInsertion('2011-11-02'));
    }
}

class Invoices
{
    private $invoiceDates;

    public function __construct($invoiceDates)
    {
        $this->invoiceDates = $invoiceDates;
    }

    public function getProgressiveNumberForInsertion($currentDate)
    {
        foreach ($this->invoiceDates as $number => $date) {
            if ($date > $currentDate) {
                $nextNumber = $number;
                break;
            }
        }
        if (!isset($nextNumber)) {
            $nextNumber = count($this->invoiceDates) + 1;
        }
        return $nextNumber;
    }
}

Now we encounter a simplification in requirements: invoices will be added to this system just as they are issued. Thus we don't have the responsibility of calculating the right point in the list where to insert them:

class Invoices
{
    private $invoiceDates;

    public function __construct($invoiceDates)
    {
        $this->invoiceDates = $invoiceDates;
    }

    public function getProgressiveNumberForInsertion($currentDate)
    {
        $nextNumber = count($this->invoiceDates) + 1;
        return $nextNumber;
    }
}

Since the parameter is not needed anymore, we start the refactoring. First, we remove the formal parameter: any actual parameter passed in will be ignored.

class Invoices
{
    private $invoiceDates;

    public function __construct($invoiceDates)
    {
        $this->invoiceDates = $invoiceDates;
    }

    public function getProgressiveNumberForInsertion()
    {
        $nextNumber = count($this->invoiceDates) + 1;
        return $nextNumber;
    }
}

Then we adjust the calls. Due to the simplification in requirements, only a single test is now needed for this feature.

This kind of test code should be unified before simplifying the method as we did in the first step, I agree. However, test code in this article series represents not only the test suite but also all the client code which calls the code undergoing the refactoring; my argument is that while removing a parameter, client code should be simplified after the called one. The reason is simply that PHP supports calls that provides additional arguments, but not calls that provides not enough arguments.

<?php
class RemoveParameter extends PHPUnit_Framework_TestCase
{
    public function testProvidesNextInvoiceNumbersForTheCurrentDate()
    {
        $invoices = new Invoices(array(1 => '2011-10-01', 2 => '2011-11-01'));
        $this->assertEquals(3, $invoices->getProgressiveNumberForInsertion());
    }
}

Now we're finished. If you have doubts about having fixed all the method calls, temporarily transform the signature into something like this:

    public function getProgressiveNumberForInsertion(InexistentClass $shouldNotBePassed = null)

and run the test suite. Any call which passes an argument (different from null) will result in an error detected by PHPUnit.

Discover the warning signs of DevOps Dysfunction and learn how to get back on the right track, brought to you in partnership with CA Technologies.

Topics:

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}