Currently an awesome RFC to introduce Named Parameters to PHP is in the voting phase. As I voted against this RFC and some people asked me about my reasoning I thought I share it here.
For me this RFC is added syntactic sugar that doesn’t solve a problem but allows for a more lazy programming style. But it introduces a lot of BC break potential by suddenly adding variable names to a public API and by introducing runtime errors due to variable naming.
— Andreas Heigl (@heiglandreas) July 10, 2020
After this tweet I had some interesting conversations on and off twitter that made me think about my take on named parameters back and forth.
And as much as I like the idea of named parameters I still see one major issue in the currently proposed implementation: Changing Parameter names.
With Named Parameters the names I give my parameters suddenly move from a mere implementation detail to part of the contract that my API specifies.
On function names
That is the same that happens with my function name or my class name – with the difference that I knew about that beforehand. And – well, let’s be honest: Naming things is hard and at least I accidentally shipped a wrongly named function in a library. So when I realized that, I had to release a new version of the library that contained the following code:
function generateSum(int $a, int $b): int
{
return $a + $b;
}
/** @deprecated Use generateSum instead */
function genreateSum(int $a, int $b): int
{
return generateSum($a, $b);
}
Yeah. You guessed what had happened. My IDE didn’t tell me. But hey. I can circumvent the issue by generating a new function – now hopefully with the correct name – and mark the old one as deprecated. Problem solved. Messy, but yeah. I deserve it!
Changing Parameter Names
But how can I do the same when I want/need/have to change a parameter name? I at least couldn’t find a solution to that in the RFC.
Given this function signature:
function myFunc($param1, $parma2);
How can I change that in a stable way?
function myFunc($param1, $param2);
/** @deprecated Use myFunc($param1, $param2) */
function myFunc($param1, $parma2);
This will result in a Fatal error: Cannot redeclare myFunc()
And sadly something like this was not mentioned in the RFC
@@NamedParamAlias('parma2','param2')
function myFunc($param1, $param2);
This would allow a transparent name change of a parameter while still allowing to generate a deprecation notice so that calling code can update their references.
So this code could be called in either way now but the first one would also emmit a deprecation notice so that I can adapt my code.
myFunc(parma2: 2, param1: 3);
myFunc(param2: 2, param1: 3);
Yes. this opens up some more questions like: What happens if I want to rename the parameter again? (You do it and ad another alias) What if I want to rename the parameter to a name that was used for a different parameter before? (You don’t!!)
This, by the way would also allow to make renaming parameters during inheritance easier:
class parent {
function myFunc($a, $b){}
}
class child extends parent {
@@NamedParamAlias('a', 'c');
@@NamedParamAlias('b', 'd');
function myFunc($c, $d){}
}
/** @var $class parent
$class = new child();
$class->myFunc(a: 2, b: 4);
So as long as this RFC can not help me with deliberately renaming parts of my public API I feel not able to say “Yes” to it.
As the question is not whether we need to rename a part of a public API but when