Introduction
Named arguments, introduced in PHP 8.0, let you pass values to a function by parameter name instead of position. They make code self-documenting, allow skipping optional parameters, and pair perfectly with constructor promotion.
Key Concepts
- Named Argument: A function argument passed as
paramName: valueinstead of by position. - Skipping Optionals: Named arguments let you specify only the parameters you need, skipping ones with defaults.
- Argument Unpacking: Spreading an associative array as named arguments with
...$array.
Real World Context
PHP has many built-in functions with five or more parameters where you only need to change the last one. Before named arguments, you had to pass all preceding defaults explicitly. Named arguments eliminate this boilerplate, especially with functions like array_filter(), setcookie(), and json_encode().
Deep Dive
Basic Syntax
Pass arguments by name:
php<?php function createUser(string $name, string $email, int $age, bool $active = true) { // ... } // Positional (old way) createUser('John', 'john@example.com', 25, true); // Named arguments - clearer intent createUser( name: 'John', email: 'john@example.com', age: 25, active: true );
Named arguments make the purpose of each value immediately clear without checking the function signature.
Skipping Optional Parameters
This is where named arguments shine:
php<?php function sendEmail( string $to, string $subject, string $body, string $from = 'noreply@example.com', array $cc = [], array $bcc = [], bool $html = false ) {} // Only specify what you need sendEmail( to: 'user@example.com', subject: 'Hello', body: 'Message content', html: true // Skip $from, $cc, $bcc );
Without named arguments, you would need to pass 'noreply@example.com', [], [] before true.
Mixing Positional and Named
Positional arguments must come first:
php<?php // OK: positional first, then named createUser('John', 'john@example.com', age: 25, active: true); // Error: cannot use positional after named createUser(name: 'John', 'john@example.com');
This rule prevents ambiguity about which parameter receives which value.
With Array Functions
Named arguments improve readability of built-in functions:
php<?php $numbers = [3, 1, 4, 1, 5, 9]; // What does ARRAY_FILTER_USE_KEY mean here? array_filter($numbers, fn($n) => $n > 2, ARRAY_FILTER_USE_KEY); // Self-documenting with named args array_filter( array: $numbers, callback: fn($n) => $n > 2, mode: ARRAY_FILTER_USE_BOTH );
The named version makes the third argument's purpose immediately clear.
Argument Unpacking with Names
Spread an associative array as named arguments:
php<?php $args = [ 'name' => 'Alice', 'email' => 'alice@example.com', 'age' => 30, ]; createUser(...$args); // Equivalent to: createUser(name: 'Alice', email: 'alice@example.com', age: 30);
This is powerful for building function calls dynamically from configuration or request data.
Common Pitfalls
- Renaming parameters breaks callers — Named arguments create a dependency on parameter names. Renaming a parameter in a library function is now a breaking change.
- Using named arguments with variadic functions — Named arguments and variadic parameters (
...$args) have complex interaction rules. Stick to positional arguments for variadic functions.
Best Practices
- Use named arguments for boolean and configuration parameters —
createUser(active: true)is much clearer thancreateUser('John', 'john@ex.com', 25, true)where thetruemeaning is unclear. - Treat parameter names as part of your API — Since callers depend on names, choose descriptive names and avoid renaming them in public APIs.
Summary
- Named arguments pass values by parameter name with
name: valuesyntax. - They allow skipping optional parameters in the middle of a parameter list.
- Positional arguments must come before named arguments.
- Associative arrays can be unpacked as named arguments with
...$array. - Parameter names are now part of your public API contract.
Code Examples
<?php
declare(strict_types=1);
class Product {
public function __construct(
public string $name,
public float $price,
public int $stock = 0,
public string $sku = '',
public bool $active = true
) {}
}
// Named arguments make constructors self-documenting
$product = new Product(
name: 'Widget',
price: 29.99,
active: false // Skip stock and sku, use defaults
);
// Unpacking from an associative array
$data = ['name' => 'Gadget', 'price' => 49.99, 'stock' => 100];
$product2 = new Product(...$data);
echo $product->name; // Widget
echo $product2->stock; // 100
?>