0

Named arguments for constructors — making object creation readable

Intermediate5 min read·php-08-015

Concept

Named arguments (PHP 8.0) allow passing arguments to a function by parameter name rather than position. This makes call sites more readable, enables skipping optional parameters in the middle of a signature, and makes code self-documenting when parameters aren't obviously identifiable from their values alone.

Syntax: functionName(paramName: value). Named and positional arguments can be mixed, but positional arguments must come before named ones.

Particularly useful for constructors: When creating objects with many optional properties, named arguments avoid the "seven booleans" problem — new Config(true, false, true, false, ...) is opaque, while new Config(debug: true, cache: false) is self-documenting.

Skipping optional parameters: array_slice($arr, 0, preserve_keys: true) — skip $length (omit it entirely) and pass preserve_keys by name. Previously this required passing null for $length, which is less clear.

Array spread of named args: PHP 8.1 allows $fn(...['name' => 'Alice', 'age' => 30]) — spreading an associative array as named arguments. Useful for calling functions with parameter lists computed at runtime.

Limitations: Named arguments can't be used with variadic functions' variadic parameters. They're also not supported in some older extensions' built-in functions (though most core functions support them in PHP 8+).

Code Example

php
<?php
declare(strict_types=1);

// Basic named arguments
function createUser(string $name, string $email, string $role = 'user', bool $active = true): array
{
    return compact('name', 'email', 'role', 'active');
}

// Positional — opaque
$user1 = createUser('Alice', 'alice@ex.com', 'admin', true);

// Named — clear intent
$user2 = createUser(
    name:   'Bob',
    email:  'bob@ex.com',
    role:   'editor',
    active: false,
);

// Skip optional parameters — you can skip 'role', only pass 'active'
$user3 = createUser('Carol', 'carol@ex.com', active: false);
// $role takes default 'user', only 'active' is changed

// Built-in function with named args
$arr = ['a', 'b', 'c', 'd', 'e'];

// Skip $length (use null position), pass preserve_keys by name
$slice = array_slice(array: $arr, offset: 1, preserve_keys: true);
// [1 => 'b', 2 => 'c', 3 => 'd', 4 => 'e']

// htmlspecialchars — no more memorizing flag order
$clean = htmlspecialchars(
    string:   $userInput,
    flags:    ENT_QUOTES | ENT_HTML5,
    encoding: 'UTF-8',
);

// Constructor with named args — DTO creation
class HttpRequest
{
    public function __construct(
        public readonly string $method,
        public readonly string $uri,
        public readonly array  $headers = [],
        public readonly string $body    = '',
    ) {}
}
$request = new HttpRequest(
    method:  'POST',
    uri:     '/api/users',
    body:    '{"name":"Alice"}',
    headers: ['Content-Type' => 'application/json'],
);

// Spread associative array as named args (PHP 8.1)
$params = ['name' => 'Dave', 'email' => 'dave@ex.com', 'role' => 'viewer'];
$user4 = createUser(...$params); // named args from associative array