
Named arguments are coming in PHP 8 - virajk31
https://stitcher.io/blog/php-8-named-arguments
======
thaumaturgy
I'm ambivalent.

There's a tension in PHP-land between PHP's roots as a low-ish level, get-it-
done, hackish language, with its big standard library and simple scalar types,
and the better-organized and quite vocal developers who want it to be more
Java-like, with great big frameworks and many deeply-nested complex class
hierarchies. Instead of unwieldy hobbyist-hacker balls of mud, you build
enterprise-scale balls of mud.

Named arguments don't do a lot for the first group. It looks like the big
point in favor is not having to look up a reference for which-arguments-go-
where in functions anymore, but a good IDE already does that for you.

But there is a common anti-pattern where you have some polymorphic function or
interface, and you want to accrete your arguments somewhere and then bundle
them up and call the function, so then you see things like [1]:

    
    
        call_user_func($function, ['length' => $n, 'foo' => $bar, ...]);
    

...and _that_ is bad because it totally bypasses all of PHP's type-checking
and leaves it up to the called function to sanity-check the input types
instead of letting the compiler do it, and basically nobody does that anyway.

So named parameters would fix that at least, which would be nice. I'm just not
looking forward to the impact this is going to have on code readability,
because everyone (including this article) is going to go, "oh, now my
parameter list is too long!", and break the function signature into one-line-
per-parameter, which is vile.

[1]: I'm guilty of this too.

~~~
pansa2
> _There 's a tension in PHP-land between [...] hobbyist-hacker [vs]
> enterprise-scale_

IMO the same tension exists in Python. The hobbyist-hackers are using the
language to write small-ish scripts, and the enterprise-scale developers are
working on million-line codebases.

Unfortunately for the hobbyist-hackers, at some point (perhaps when the BDFL
started working at Dropbox), the focus of the language shifted from the first
group to the second. That's why, for example, Python now has a complex type
system - that many developers never use.

~~~
iso1631
> IMO the same tension exists in Python. The hobbyist-hackers are using the
> language to write small-ish scripts, and the enterprise-scale developers are
> working on million-line codebases.

It's an endless cycle in all aspects of IT, the conflict between small tech
and enterprise tech

Large tools from bureaucratic enterprises are useless (that's a given)

Shadow IT built around hacker tools gets the business goals through

Enterprise IT see that these tools are popular and actually meet business
goals, but they didn't invent them

Enterprise IT attempts to justify itself and find something approximating the
usability of the good tools from some "safe" vendor like Oracle, Microsoft,
etc. After all nobody got fired for buying IBM.

Enterprise IT spends a fortune, everyone hates it, but old tools are defunded
so can't be used.

Shadow IT build new ecosystem around different hacker tools to get the
business goals through

And the cycle continues.

~~~
majewsky
> Large tools from bureaucratic enterprises are useless (that's a given)

There are plenty useful tools that are large and built by bureaucratic
enterprises. Stuff like ERP systems just has so many features to cover and tax
laws to implement that it most likely can genuinely not be built by a small
team.

(Disclosure: I work for such an enterprise, though I'm not involved in the
development of software sold to customers.)

------
jonplackett
This was my favourite thing about learning Swift. I hadn’t used a named
argument language before. It feels very relaxing knowing that the compiler can
check all these things for you. I haven’t used php for years but it’s cool to
see it adopting this. Maybe I’ll give it another go!

~~~
DaiPlusPlus
C# has had named arguments for a while now too - and I’m in love with them.
They’ve helped me avoid many ugly bugs caused by refactoring, such as when a
method has many parameters with the same type - and a refactoring reordered or
added/deleted parameters - thanks to named-parameters the call-sites still
worked instead of silently failing (because the call-site would still be type-
correct and compiled, even if it was intent-incorrect).

My _only_ peeve is that VS still doesn’t let you style/colour named-argument
labels in a different colour, so it does add to visual-noise in the editor.

Adding labels to every argument is just silly, so I do have a personal hard-
and-fast rule that any call-site of a method with literal arguments must be
explicitly labelled (especially booleans!), and any call-site of a method with
consecutive homogenous typed parameters must also be labelled - these rules
have worked out fantastically for me.

------
hnarn
> named arguments allow you to pass input data into a function, based on their
> argument name instead of the argument order

Granted, I'm not a PHP developer, but I can't understand why a change like
this would be controversial. It sounds like it's optional, and would help
greatly to reduce mistakes when passing arguments to functions? Having
multiple lines of things being passed to a function may look odd to some, but
couldn't the same argument be made as with arrays, that one line per "thing"
makes sense, if nothing else to clean up diffs when collaborating on code?

~~~
userbinator
_Granted, I 'm not a PHP developer, but I can't understand why a change like
this would be controversial. It sounds like it's optional,_

It's only optional when you're writing code. Even if you don't use features in
your own projects you're undoubtedly going to be reading a lot of other's
code, which may or may not use these features, and from that perspective added
language complexity is a burden.

~~~
hnarn
Sure, but it's only confusing when reading it if it's hard to implicitly sort
of understand what's happening when you're not used to it, right? Named
arguments seem pretty straightforward to me, in the sense that it's relatively
obvious what they are when you see them. It's not exactly like a new operator
or some kind of symbol unique to the language that is almost impossible to
understand without looking it up.

------
matsemann
Not sure if the standard library has evolved since my PHP days, but this would
at least solve the "key / haystack" issue. In which lots of the standard
library had different orders in which parameters are passed. One can finally
pass them named and no longer have to care about the order. This may also have
been solved by better tooling since then, though.

~~~
disiplus
a proper IDE solves that, but i always laugh when getting back to php why they
made array_map and array_filter switch parameter order.

~~~
Denvercoder9
> why they made array_map and array_filter switch parameter order

It kind of makes sense if you look at the signatures (array_map takes a
callable and a variable number of arrays, while array_filter takes a singe
array and an optional calable), but yeah, it's horrible to use.

------
skocznymroczny
Named arguments is a no-brainer for me for any kind of programming language. I
am hoping D adopts named arguments too, although it's a very uphill battle
there with many programmers coming from C/C++ background being opposed to it
in the name of API stability.

~~~
raxxorrax
I agree, it is a sensible improvement. What I don't like is spread operators
in every form, but I can certainly live without

    
    
      funcy(null, null, null, null, null, null, cake, null, lie)...

~~~
spaetzleesser
I remember when dealing with Excel COM having lists of 30 arguments and more.
And it made a difference if parameter 26 or parameter 27 was null.

------
hprotagonist
in python i started writing any function that takes >2 arguments as either

    
    
      def foo(*,a,b,c)...
    

or

    
    
      def foo(obvious_and_required_thing, *, a,b,c) ...
    

and noticed an immediate improvement in clarity.

~~~
throwaway43234
I understand that this is standard practice by now, but this is one of those
cases where I can't help but feel the language design team strayed too far
from the original spirit of python. Now there's yet another possible
interpretation of an asterisk: multiplication; splatting; exponentiation;
declaring variadic arguments; and now declaring that all subsequently declared
arguments are to be keyword-only. And I understand that it sort-of relates to
declaring variadic arguments, but it certainly isn't declaring variadic
arguments, and in my opinion reusing the same token in the same syntactic
construct for two wildly different purposes is destined to cause confusion.
For evidence, see the other replies: people don't know about this and can't
easily tell what it does. This runs counter to the Zen: "Readability counts",
"Explicit is better than implicit", "Special cases aren't special enough to
break the rules.", etc.

I think JavaScript got this right where the semantic resolution steps of
arguments pretty closely follow the steps for assignment, which means once
someone understands the basic idea of object destructuring they get named
arguments for free, in the form of destructured object parameters:

    
    
        const foo = (positionalArg1, {namedArg1, namedArg2 = 'foo'}) => { ... }
        foo(1, {namedArg: 'bar'}) 
        // resolved same as 
        const [positionalArg1, {namedArg, namedArg2 = 'foo'}] = [1, {namedArg: 'bar'}]

~~~
kabacha
I'll disagree with you here. In Python `*` is already a extremely popular
symbol for expanding and there's no usage conflict between expand and numeric
multiplication. This change gels really nicely with the rest of expand
ecosystem.

I think it's much more beautiful and convenient than your JS example which in
all honesty looks necessary cluttered and ugly.

~~~
jakear
But there’s no expanding happening here? So why take a token that’s
immediately recognizable as either “expanding” or “muliplying-ish” and extend
it to mean “or enforcing named parameters and not expanding”?

> cluttered and ugly

I won’t argue with you about visuals because I don’t think they’re all that
important. But, I think it’s undeniable that reusing the same syntactic
concepts across different semantic use cases is quite a lot more _logically_
clean & beautiful than introducing new syntax that other HN commenters with
past python experience can’t even understand. If someone sees the JS named
parameter syntax at a declaration and has any JS experience, they’ll almost
certainly figure out what to do - if someone sees the asterisk, even with
Python experience, they’ll think “what the heck is this asterisk?” And again,
the other commenters on this thread are clear evidence that this is indeed as
unintuitive as I describe.

~~~
masklinn
> But there’s no expanding happening here?

There's a collection of 0 arguments. the "∗" was introduced specifically as a
shortcut for:

    
    
        def foo(a, *ignore, b):
            if ignore:
                raise TypeError
    

forgoing the name simply signals to the language that it should collect
nothing.

It's a logical extension of the assumption that anything which follows `∗arg`
is a keyword-only parameter.

------
chx
There was a time when I would've been all-out in favor for this because one of
the most often used functions in Drupal had no less than seven arguments:
[https://api.drupal.org/api/drupal/includes%21common.inc/func...](https://api.drupal.org/api/drupal/includes%21common.inc/function/l/5.x)
it being seven, the running joke was knowing the Seven Parameters Of L is our
initiation rite.

Then the options collapsed into an array
[https://api.drupal.org/api/drupal/includes%21common.inc/func...](https://api.drupal.org/api/drupal/includes%21common.inc/function/l/6.x)
and that was in 2008.

And then URLs in 2015 became a value object and while you can still pass
absolute => TRUE in options if you really want to, you can just call
setAbsolute() on the object.

I guess if PHP core adopts this , phpstorm will quickly adopt as well and
typing strpos( will immediately expand to strpos(haystack: , needle: so you
can just fill that in. I guess? so maybe a reluctant yes but I am a bit wary
of the APIs that will follow from this. I guess I have slowly grown fond of
value objects? I must be getting old.

------
stunt
Named arguments are great where you can't do it without them. It's good that
language provides you the tool. And it's your job to as a developer to not
abuse it.

------
perlgeek
Two of the languages I use most often (Python and Raku (formerly known as Perl
6)) have named arguments, and it improves clarity of code tremendously.

I don't know how well it fits into PHP, but if it's anything like in python or
raku, go for it! :-)

------
gremlinsinc
It feels like an anti-pattern, but I've been burned so many times by
forgetting what order things go in, and not wanting to waste the 10 seconds to
go look, that in a lot of methods if I have more than 2 parameters, I'll
convert it to an array.

the associative array, thus giving me the named attributes.

It's a bit hackety, but the new named params looks like a much more elegant
solution.

One issue also is if you have a method that takes 3 arguments and the 2nd is
an integer not a string, and you pass a string you'll get an error... using an
array, you can just test if the array key exists or not, and skip
functionality as dictates by what's passed in.

------
Yoofie
When I was learning Verilog HDL, named parameters are commonly used and highly
encouraged. I wondered why more traditional programming languages didn't use
this concept aswell for the same reasons the article goes into.

~~~
nobleach
I first ran into them in Python myself. After using kwargs for the first time,
I wondered the same thing. While I try to limit the number of args I pass to
functions and methods, sometimes it simply can't be helped. Kotlin is a
wonderful example of how both positional AND named arguments can be supported.

------
zerocrates
I get why it's being done that way, but the bit about parameter names being
allowed to vary in subclasses feels... non-great.

As a result you can't really safely use named parameters on calls without more
extensive control of what you're being passed: even if you typehint to a class
or interface, you can just get passed a parameter-name-changed subclass that
breaks your call anyway. Feels like a "strict" type warning would be in order
rather than just silent acceptance of the variance combined with a hard error.

~~~
masklinn
> I get why it's being done that way, but the bit about parameter names being
> allowed to vary in subclasses feels... non-great.

As justified, it feels necessary for backwards-compatibility reasons since
named arguments are not _defined_ as named, just _used_ as such.

~~~
zerocrates
Still feels like a "strict warning" situation. Again, I can see why they have
to do it that way because this was just not previously part of the public
interface to a function, but it is now, so there should be some indication
that doing this name mixing is, in fact, Now A Problem.

I guess it can just be handled on a static analysis/code-checker kind of
level, but the language _already_ has a system for emitting these kind of
"code standards" warnings.

------
segmondy
PHP will eventually evolve into Java. The only difference will be the runtime.

~~~
ragnese
I've been saying for a while now that PHP today is basically Java - generics +
better nullability and with a much worse standard library.

------
cletus
So here's a good test for the value of [language feature X]:

 _Do people naturally try and reinvent that feature in its absence?_

So for named parameters you have:

1\. Javascript would often be written with methods with a single "options"
parameter, where "options" is an anonymous object and basically a map;

2\. Day-to-day I write Hack. Many functions are similarly written taking a
shape as an argument. Shapes are structs, basically, but the typechecker is
smart enough to treat them as a well-defined by anonymous type.

3\. I've also seen C code that does much the same with things structs.

Empirically there seems to generally be a demand for this kind of feature and
it makes sense: long parameter lists are tedious and error-prone (have you
ever seen a function that has 3 boolean parameters in a row?) where people try
and be helpful by providing "optional" parameters (which are really just
parameters with default values).

So sure, I'm all for named parameters.

~~~
hajile
JS records are superior.

I can create an object, then dynamically add various parameters before sending
them rather than bogging down the function call. Destructuring in particular
ensures this is pleasant for both the function creator and consumer.

You see a similar debate between StandardML and Ocaml though on a more
fundamental level. SML uses structurally-typed records, so you can instantiate
an inline record without needing to add any types and the function will
destructure it for use. Ocaml went with nominal typing making this painful, so
they added a complex optional argument syntax instead. Typescript is also
structurally typed and I'd guess this is the reason.

------
crazygringo
I'm so happy to see named parameters become more common.

They're absolutely critical to writing code that is easy to _read_. The name
of a function tells you what it does, arguments equally need names to tell you
what _they_ do.

Even if I have a great IDE, I don't want to hover/cursor over the line to see
what each argument does, each random "0" or "null" or "1" or whatever. There
are also plenty of times I'm viewing code that isn't in an IDE, like a diff.

Obviously they're not always needed, like in functions that take only one or
two required obvious parameters.

But otherwise, they can make the intent of a line of code obvious at a glance,
and are a _huge_ step toward making code self-documenting.

I just can't believe this is a change that's only picking up now, rather than
20 years ago.

~~~
linux2647
On the other hands, many JetBrains IDEs will insert the names of parameters in
a function call inline to help identify what passed variable belongs to which
parameter. It’s not inserting it in the actual source code, but exists purely
in the UI ([https://www.jetbrains.com/help/clion/parameter-
hints.html](https://www.jetbrains.com/help/clion/parameter-hints.html)). It’s
useful if $LANG doesn’t have named parameters

------
slifin
The fact it errors if you over supply the function arguments is a bit worrying

Adding a key to an array shouldn't be a breaking change, if you over supply a
function by position today PHP doesn't error

~~~
Denvercoder9
> if you over supply a function by position today PHP doesn't error

I'd argue that this it the worrying part. How often do you intentionally
supply an extra argument, and how often is it an accident? I'd take the
warning.

~~~
slifin
It's important to recognise what we can't do with that error in:

    
    
        <?php
        
        $user = [
          'age' => 25,
          'name' => 'Brent',
          'email' => 'brent@stitcher.io',
        ];
        
        function send_email(string $name, string $email) : void
        {
            //...
        }
        
        send_email(...$user);
    

^So this would error, even though it's a nice specification as far as the
function is concerned, I'm all for strict static analysis but not at the
expense of open maps

"If your program deals with information, these are among your primary
problems: information is sparse, incrementally accumulated, open/extensible,
conditionally available, formed into arbitrary sets in different contexts,
merged with other information etc."

~~~
Denvercoder9
While you're right, I don't think that's something commonly used. I definitely
can't remember the last time I wrote code where this would be useful.

That might be because usage of associative arrays is more or less discouraged
in modern PHP in favor of value objects (especially with property promotion in
PHP8). Main reason for that is that this usage is horrible for IDEs and static
analysis. Way too easy to rename a parameter and create a runtime error.
Typing is also enforced at usage instead of creation, and you have to repeat
the type information in every function signature.

------
DeusExMachina
It's pretty funny that named arguments were, for a long time, a feature
present only in Objective-C of all the languages I tried (and I tried many).

It was one of the features of Objective-C I liked and I missed in any other
language. I also think they were one of the reasons many developers disliked
the language.

When Swift was introduced, it got named parameters from Objective-C and now
they are getting more "mainstream", entering in a language much more
widespread than the former two.

~~~
moloch
Python has had named arguments for a long time (since v1.4), which is arguably
more widespread than PHP or Swift.

------
nurettin
There are a lot of arguments surrounding this subject. Just came in here to
chime about how I miss named arguments in c++. Sure, I can emulate them [0]
but at the cost of ide support, runtime and compile time.

[https://github.com/nurettin/pwned/blob/770144a15efe7ab96bf4d...](https://github.com/nurettin/pwned/blob/770144a15efe7ab96bf4d0414bcaf7424e9a9118/parameters/tests.cpp#L15)

~~~
cma
They are effectively in C++20 without real penalty (designated initializers).

~~~
nurettin
Yes, designated initializers help initialize a dto, much like what C# did back
in 3.0 times. I wish they did something similar to function parameters so we
didn't even have to create a data transfer object.

------
conradfr
I've often wondered why there was no "default" keyword, so you could call a
function like this:

foo('first arg', default, 'third arg');

Named parameters will do but they are more verbose.

Speaking whishes, method overloading would be great.

~~~
manyxcxi
Having switched from 80% Java (20% about 5 other languages) to probably 75%
Kotlin over the last year, one of my absolute favorite things named arguments.

When you name your arguments, simply supplying them will use the default if
one has been specified. If one hasn’t been specified then you must provide it
when calling and your compiler/IDE will definitely let you know.

I used to go out of my way with method overloads, JavaDocs, argument
@annotations, and Builder classes in order to get this same level conciseness
and cleanliness in my Java code. It is extra work (even with Lombok) but I
personally can’t stand when I don’t keep it clean like that. Understandably a
lot of other developers on my teams don’t always go to the same lengths.

I honestly haven’t ready the details on PHP’s plan for this, but with Kotlin’s
names arguments I’ve found almost no need of method overloading anymore- most
of those input variations are now covered (except for when you’ve got
different types coming in, which usually can be handled with a common
interface or base class).

~~~
conradfr
Yeah I'm totally fine with named arguments, I even thought they would come
sooner (I've been doing PHP since 1998 so I have some perspective ahah).

And yes overloading is more about different types for me. I guess I got
accustomed to it with C# and nowadays Elixir. PHP 8 has union types so I guess
it will do.

------
ThomWilhelm3
I always wonder why PHP never seems to favour making breaking changes to keep
things cleaner, if you aren't going to improve language constructs in a major
version, when will they be cleaned up?

~~~
tonyedgecombe
I think that post Python 3 nobody is going to do that.

It would be interesting to see a fork which removed all the crud though.
Something that was easy to use for the person doing occaisional web work or
beginner but without the traps and pitfalls.

~~~
echelon
Python 3 attempted too much change at once. The Python folks could have spread
incremental rollout of the changes across several major version numbers and
probably not have faced such slow adoption.

~~~
pansa2
> Python 3 attempted too much change at once.

Python 3 got this so, so wrong. It changed enough to break everyone's code,
but not enough to make upgrading worthwhile.

It could have changed more, or changed less - done right, either would have
been better than what actually happened.

------
thinkindie
I really love this new feature however my only concern is that renaming some
parameters will trigger a lot of changes in other places as a side effect,
thus polluting diffs.

~~~
stinos
I get what you mean, but I remember at one point going through some kind of
'oh no, it's a large diff' or even 'do not do this because the diff will
increase' phase. And I realized that's just not ok. There's already enough
things to keep in mind when programming, adding an extra one just because some
external tool which actually doesn't have a lot to do with how the code works,
i.e. holding back changes because of diff, just isn't worth it.

Now, I admit cluttered diffs can be a problem, but there are workarounds: more
fine-grained commits (especially separate commits for renames only) and better
diff display. As an example of the latter: another commnter mentions one
argument per line produces better diffs. It does for your standard display
with +++/\---, but tools like Sublime Merge have this covered and siplay the
change in such a way you can immediately see what argument changed it's name,
inline in the code. If it's was just a typo fix it will usually only highlight
the changed character(s) not the complete name. Even going from all arguments
on one line to one agrgument per line is covered, since it'll just display it
as added whitespace and won't highlight the argument themselves indiacting
they did not change.

~~~
majewsky
My biggest pet peeve is when I meticulously craft a feature branch with
commits neatly separated by subtopic so that it's pleasant to review... and
then the reviewer just takes a glance, writes "lgtm" and squash-merges.

------
mokanfar
_It 's beginning to look a lot like -- typescript_

~~~
The_rationalist
generally yes, but specifically here typescript does not have named parameters
(yeah you can emulate with a hack through object literals which is sad)

~~~
chmod775
What's sad about it? Having interfaces defining the arguments of functions
with complex parameters in a type safe manner and with support for auto-
completion is one of the greatest thing to ever happen to JavaScript in my
opinion. And you get named function arguments as a by-product of something way
more powerful than just that.

------
The_rationalist
Ultimately every high level languages are converging to have the feature set
of Kotlin, its nice to see them getting closer and closer.

~~~
rbanffy
Python has it since ever.

~~~
sanxiyn
Common Lisp had it earlier.

~~~
rbanffy
Common Lisp had everything before every other language.

