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