Some Aging Parameters

Parameters are part of the signature of methods and functions. They are one of the ways to inject data into a piece of code, for it to be processed. PHP has a lot of options and they have been available since ever. They are easy to find in recent and legacy code.

Like everyday’s code, parameters tend to grow old and require maintenance. They come and go, and move around and get renamed. Each transition is a new challenge to refactoring, which mean there will be traces of evolution right in the code. In this article, we’ll code some of the remainers of such evolutions.

Let’s review some sicknesses of parameters :

  • The removed parameter
  • The unused parameter
  • The cancelled parameter
  • The hiding parameter

Parameters and arguments

A side note, about the difference between parameters and arguments.

Parameters are in the definition and the body of a method or a function, while arguments are inside a method or function call. They are two distinct sides of the same data, and they share names and options (typehints, reference, variadic,…) but they are distinct.

The removed parameter

The removed parameter is a parameter that was dropped, but the corresponding argument is still in use.

<?php

function foo($a, $b) {}

$x = goo();
foo(1, 2, $x);

?>

This means that the third argument is passed, but not processed.

Note that the extra argument might be processed : this happens when the last argument is variadic, or if the funcgetargs() function, and similar, is used.

PHP doesn’t report any error when the call doesn’t match the signature : the arguments are processed as they are provided, and any extra argument is omitted.

That way, the only visible artefact is the extra parameter litering the code. It is rather simple to fix : remove the argument in the code.

And, by extension, all the code that was needed to create the argument. The example above show the last argument being fetched from the goo function : in fact, the whole call is now useless.

[Wrong Number Of Arguments]

The unused parameter

A close cousin of the removed parameter is the unused one. This time, the argument is never explicitely used in a call. Then, the method uses the default value.

<?php

function foo($a, $b = 1) {}

foo(1);
foo(1);
foo(1);
foo(1);

?>

When the method has no default value, PHP raises an error : this is visible and easy to spot. By removing the default value, the parameter forces any calls to provide an explicit value.

On the other hand, when a default value is provided, it might address the most general case, yet leave an option for more specific and rare situations. It is one case of Reserved For Future Use (RFU). Such parameters are nice in the early stages of development. After a while, it is worth reviewing all the calls to the method, to check if the parameter is actually used or not.

And when it is not, it might be removed.

[Unused parameter]

The cancelled parameter

The cancelled parameter appears when a parameter has to be removed, but is more difficult to update without impacting significantly the calling code. In the following code, the first parameter has to be set in stone, but there are already a lot of calls to it, making it difficult to update.

<?php

function foo(int $a, string $b = 'c') {
    $a = 2;
}

foo(1, 'b');
foo(2, 'b');
foo(3, 'b');
foo(1, 'b');

?>

Here, the parameter has been kept in the signature, to keep the current code working. Yet, the incoming value is totally ignored, and forced to a defined one.

This quick-fix makes documentation quite difficult : a useless parameter means that the call must use a filler, and then, typehinting might complain about it, even though the argument is later ignore : for example, using a string in the code above blocks the call.

It appears in situations where the calling code cannot be easily modifiable : for example, with legacy applications, or external user. Removing the parameter means documenting it, and explaining to all how it works.

Other options include relying on named parameters to skip any unwanted parameters, or creating a relay method, which has the old signature and drop the unwanted parameter to call the new signature.

[Cancelled Parameter]

The hiding parameter

Finally, there is the hiding parameter. This happens when the parameter is used, but under another name. Basically, the argument has a name, and the parameter has another one.

<?php
function foo(int $a) {
    $b = $a;
    return $b - 2;
}
foo(1);
?>

The example is simplistic, so, let’s devise two actual ground stories of hiding parameters.

The first one is the copy-paste of code from known sources. When the copied code is too long, it might be too much to rename one of the variables, and make it a parameter. Then, the parameter is named, poured into the variable, and used as is. Sadly, this happens more than expected.

The second situation is the documentation of the method. Until PHP 8.0, parameters names didn’t matter, except for documentation. The name of the parameter is significant, so it is nice to give is a good name. Yet, it was a totally internal matter so far.

With PHP 8.0, named parameters are also used outside the method, and become part of the API. Using non-descript names is not possible anymore, as those names have a value in the calling code.

In both cases, refactoring the code with a meaningful name is much better. It doesn’t take much time, and IDE do help with such rewrite.

[Parameter Hiding]

Conclusion

Hopefully, running into those patterns is not common. The removed parameter is easy to spot, as long as one has the knowledge about it; the unused parameter is very difficult to track, as it implies checking every usage; the cancelled parameter requires a trained eye and the hidden parameter is usually a surprise, more than anything else.

All those situations may endure for a long time, as they do not report any problem. This is an exact application of the saying : if it works, don’t fix it. The impact on the code might appear elsewhere, in the skewed documentation, the surprising code or a vague feeling of unexplicable things.

The best solution is to refactor them, into a single functioning or removed argument. To detect it, static analysis does help by searching those rare but wasteful code patterns. The last decision is then: when to refactor them.