Named arguments and open source projects
There are a few well known open source maintainers within the PHP community against the use of named arguments, citing maintenance overhead and backwards compatibility problems as reasons not wanting to use them.
I want to nuance those arguments a little bit.
# What's causing backwards compatibility problems?
The main fear is that supporting named arguments in, for example, a framework or open source package will increase the risk of breaking changes.
Imagine a package or framework exposing this class:
class QueryBuilder { public function join( string $table, string $leftColumn, string $rightColumn, string $type ) { /* … */ } }
The problem with named arguments is that if users call this function with them, the framework now needs to treat parameter name changes as possible breaking ones:
$query->join( type: 'left', table: 'table_b', leftColumn: 'table_a.id', rightColumn: 'table_b.table_a_id', )
If the framework wants to rename leftColumn
and rightColumn
to simply left
and right
, the above code — userland code — would break.
Here's the thing: no framework or package can prevent users from using named arguments, there simply isn't a way to disallow them. So either, as an open source maintainer, you:
- treat argument name changes as breaking as soon as you support PHP 8;
- ask users not to use named arguments; or
- let users deal with those breaking changes themselves, and don't worry about it.
Being an open source maintainer myself: I choose option three. First of all: argument name changes only rarely happen; and second: I trust my users to be professional developers and know the consequences of using named arguments. They are smart grown ups, it's their responsibility.
So in summary for this first part: there's nothing the framework can do to prevent this kind of backwards compatibility issues besides making a note in the README on how they deal with argument name changes. Be consistent with whatever policy you choose, and you're fine.
# Named arguments as a cleaner syntax to deal with array data
The second way named arguments can be used, is in combination with variadic functions, essentially becoming a — in my opinion cleaner — shorthand for passing arrays of data:
$user = User::create( name: 'Brent', email: 'brendt@stitcher.io', company_id: 1, );
This is possible thanks to named arguments playing well together with variadic functions:
class User { public function create(...$props) { /* … */ } }
Passing a named argument list into this variadic create
function will result in an array like this:
[ 'name' => 'Brent', 'email' => 'brendt@stitcher.io', 'company_id' => 1, ]
Rewriting the above example without named arguments but arrays instead, would look like this:
$user = User::create([ 'name' => 'Brent', 'email' => 'brendt@stitcher.io', 'company_id' => 1, ]);
I know which one of these two approaches I prefer. Disclaimer: it's the one that has better syntax highlighting and is shorter to write.
Here's the kicker: there isn't any possibility for breaking changes, because there aren't any hard coded argument names to begin with!
We really need to be more thoughtful about claiming that we cannot support named arguments in our open source packages because of backwards compatibility issues. In the first case there's nothing you can do either way, and the second case doesn't pose any danger of breaking changes.
Don't you agree? Send me an email or tweet and we can further discuss it. I'm open to be proven wrong.