Introduction
Named arguments (or "named parameters") are one of my favourite features added to PHP back in version 8.0. I feel like they really help to improve the readability of my code and make it easier to understand what's going on.
In this article, we're going to take a look at what named arguments and the benefits they provide. We'll also quickly look at a few gotchas to be aware of when using them.
Named Arguments in a Nutshell
Put simply, named arguments allow you to pass arguments to a function or method by specifying the parameter name followed by a colon and then the value. For example, let's say we have a function called greet
that takes two parameters:
1function greet(string $name, string $greeting): string2{3 return "{$greeting}, {$name}!";4}
Using positional arguments (that you'd typically use), we'd call this function like so:
1echo greet('Ash', 'Hello');
But with named arguments, we can call this function like so:
1echo greet(name: 'Ash', greeting: 'Hello');
By using named arguments, we can instantly see what the intention of each parameter is.
What Problem Do Named Arguments Solve?
I think the best way to really understand the benefits of using named arguments and the problem they solve is to look at a slightly more in-depth example.
Let's say you have a service class (we'll look at it soon) that allows you to create a new user. We might call a createUser
method on the service class like so:
1use App\Services\UserService;2 3$userService = new UserService();4 5$user = $userService->createUser(6 'Ash',7 'mail@ashallendesign.co.uk',8 true,9);
From looking at the code above, you can probably guess what the first and second parameters are (the name and email address). But what is the third parameter?
If you came across this code in your project, you might now have to click through in your integrated development environment (IDE) to see what the third parameter is. Having to do this can add friction to the development process and slow you down because it's not immediately obvious what the parameter is.
This is where named arguments come in.
Let's take a look at the createUser
method signature:
app/Services/UserService.php
1namespace App\Services;23use App\Models\User;45class UserService6{7 public function createUser(8 string $name,9 string $email,10 bool $sendWelcomeEmail,11 ): User {12 // Create the user13 }14}
We can see in the method signature that the third parameter is used for specifying whether to send a welcome email to the user. By using named arguments, we can make the code more readable and self-explanatory:
1use App\Services\UserService;2 3$userService = new UserService();4 5$user = $userService->createUser(6 name: 'Ash',7 email: 'mail@ashallendesign.co.uk',8 sendWelcomeEmail: true,9);
As we can see in the code above, we've used named arguments to make it clearer what each parameter is for. This means the code is easier to read at first glance and should help reduce the time it takes to understand it when you come back to it at a later date.
The really cool thing about named arguments is that you can also use a mixture of named and positional arguments (as long as the named arguments come after the positional arguments). So let's say we only want to use named arguments for the third parameter, we could update our function call like so:
1use App\Services\UserService;2 3$userService = new UserService();4 5$user = $userService->createUser(6 'Ash',7 'mail@ashallendesign.co.uk',8 sendWelcomeEmail: true,9);
Benefits of Named Arguments
Using named arguments in your code can provide several benefits:
Improved Readability
As we've mentioned, the thing that I've found most beneficial when using named arguments is improved readability. By using named arguments, you can make your code more self-explanatory and easier to understand at first glance.
This can be really useful when revisiting code you've written a while ago, or when you're working with a team of developers.
It almost acts as a form of code-as-documentation because you can provide hints to the developer reading the code about what each parameter is for.
Skipping Optional Arguments
Another benefit of named parameters is you can use them to reduce the number of optional arguments you need to pass to a method if they match the default values.
For example, let's imagine we have the following createUser
method:
app/Services/UserService.php
1namespace App\Services;23use App\Models\User;45class UserService6{7 public function createUser(8 string $name,9 string $email,10 bool $sendWelcomeEmail = true,11 bool $isVerified = false,12 string $role = 'user',13 string $locale = 'en',14 ): User {15 // Create the user16 }17}
As a side note, this method signature is a code smell (it has too many parameters) and could probably be refactored to be more maintainable, especially by passing a data transfer object (DTO) to the method instead. But for the purposes of this example, let's keep it as is.
In the method, we're only actually enforcing the first two parameters ($name
and $email
). The rest of the parameters have default values, so they're optional.
Let's imagine we want to create a user with all the default values except from the locale
. Using positional arguments, we'd have to pass the default values for the sendWelcomeEmail
, isVerified
, and role
parameters:
1use App\Services\UserService; 2 3$userService = new UserService(); 4 5$user = $userService->createUser( 6 'Ash', 7 'mail@ashallendesign.co.uk', 8 true, 9 false,10 'user',11 'es',12);
Whereas, with named arguments, we only need to pass values to the optional arguments if we want to override the default values. So we can skip the sendWelcomeEmail
, isVerified
, and role
parameters:
1use App\Services\UserService;2 3$userService = new UserService();4 5$user = $userService->createUser(6 name: 'Ash',7 email: 'mail@ashallendesign.co.uk',8 locale: 'es',9);
Pretty cool, right?
Things to be Aware Of
It's worth noting that a named argument should match exactly in the method signature as it does in the function call. This means if you misspell the named argument or the argument is renamed, an error will be thrown.
For example, let's take our createUser
method from earlier. Imagine the sendWelcomeEmail
parameter was renamed to sendWelcomeNotification
like so:
app/Services/UserService.php
1namespace App\Services;23use App\Models\User;45class UserService6{7 public function createUser(8 string $name,9 string $email,10 bool $sendWelcomeNotification,11 ): User {12 // Create the user13 }14}
If we didn't update our code from above, this would throw an error:
1Unknown named parameter $sendWelcomeEmail
Instead, we'd need to update our function call to match the new method signature:
1use App\Services\UserService;2 3$userService = new UserService();4 5$user = $userService->createUser(6 name: 'Ash',7 email: 'mail@ashallendesign.co.uk',8 sendWelcomeNotification: true,9);
For this reason, it's important to be aware of method signature changes. If you own the method you're changing, it's much easier to spot these changes. But if you're working with third-party libraries, you'll need to keep an eye on the documentation or changelog to see if the method signature has changed. If you don't notice the change, you'll likely see an error thrown in your application.
Another great way to catch these errors is to have a good test suite in place or use a static analysis tool like PHPStan. So you'll likely find it beneficial to run your test suite after updating your Composer dependencies to catch any breaking changes. In fact, if you're interested in learning about how to build a test suite like this, I talk about how to do it in my book "Battle Ready Laravel".
Conclusion
Hopefully, this article showed you the benefit of using named arguments in your PHP code. It should have also shown you the things to be aware of when using them.
If you enjoyed reading this post, you might be interested in checking out my 220+ page ebook "Battle Ready Laravel" which covers similar topics in more depth.
Or, you might want to check out my other 440+ page ebook "Consuming APIs in Laravel" which teaches you how to use Laravel to consume APIs from other services.
If you're interested in getting updated each time I publish a new post, feel free to sign up for my newsletter below.
Keep on building awesome stuff! 🚀