Aikido

Why you should use named arguments in Python and PHP

Readability

Rule
Use named arguments for clarity
Named arguments make code self-documenting 
and prevent parameter order mistakes.
Use named arguments when functions have more
than 2-3 parameters or boolean flags.

Supported languages: Python, PHP

Introduction

Functions with multiple parameters become unclear when you see the call site. Reading sendEmail('user@example.com', true, false, 30) requires looking up the function signature to understand what true, false, and 30 mean. Named arguments solve this by making each parameter's purpose explicit at the call site. They also prevent bugs from parameter reordering when function signatures change.

Why it matters

Code maintainability: Named arguments document intent at the call site without requiring constant reference checking. When you see sendEmail(to: $email, retry: true, async: false, timeout: 30), you understand exactly what each value controls. This eliminates confusion during code review and makes debugging faster since you don't need to mentally map positional arguments to parameter names.

Security implications: Parameter order mistakes in security-critical functions can create vulnerabilities. Swapping the $username and $password parameters, or accidentally passing the plaintext password where the hashed password belongs, fails silently with positional arguments. Named arguments force you to explicitly state which value goes where, preventing these dangerous mistakes.

Refactoring safety: Adding optional parameters to existing functions breaks all call sites with positional arguments unless you append them at the end. Named arguments let you add, reorder, or change parameters without breaking existing code, as long as parameter names stay consistent. This makes APIs more stable and evolution less risky.

Code examples

❌ Non-compliant:

function createUser($email, $password, $role, $verified, $sendEmail, $retryCount) {
    $hashedPassword = password_hash($password, PASSWORD_BCRYPT);

    $user = User::create([
        'email' => $email,
        'password' => $hashedPassword,
        'role' => $role,
        'verified' => $verified
    ]);

    if ($sendEmail) {
        sendWelcomeEmail($user->email, $retryCount);
    }

    return $user;
}

// Unclear what each parameter means
createUser('user@example.com', 'secret123', 'admin', true, false, 3);

Why it's wrong: The call site provides no context for what true, false, and 3 mean, requiring constant reference to the function signature. Swapping $role and $password or $verified and $sendEmail would fail silently, potentially creating security issues.

✅ Compliant:

function createUser(
    string $email,
    string $password,
    string $role = 'user',
    bool $verified = false,
    bool $sendEmail = true,
    int $retryCount = 3
) {
    $hashedPassword = password_hash($password, PASSWORD_BCRYPT);

    $user = User::create([
        'email' => $email,
        'password' => $hashedPassword,
        'role' => $role,
        'verified' => $verified
    ]);

    if ($sendEmail) {
        sendWelcomeEmail($user->email, $retryCount);
    }

    return $user;
}

// Self-documenting call site
createUser(
    email: 'user@example.com',
    password: 'secret123',
    role: 'admin',
    verified: true,
    sendEmail: false,
    retryCount: 3
);

Why this matters: Each parameter's purpose is explicit at the call site, making the code self-documenting. Parameter order mistakes are impossible since you explicitly name each argument, and adding new optional parameters won't break existing code.

Conclusion

Use named arguments for functions with more than 2-3 parameters, boolean flags, or similar types appearing consecutively. The slight verbosity at the call site pays for itself in clarity, safety, and maintainability. Reserve positional arguments for simple functions where parameter order is obvious and unlikely to change.

FAQs

Got Questions?

When should I require named arguments versus making them optional?

In Python, use * to force named arguments: def func(a, b, *, named_only). In PHP 8+, named arguments are always optional but you can encourage them through documentation. Require named arguments when parameter order is unintuitive or when similar types appear consecutively (multiple strings, booleans, or integers).

Do named arguments impact performance?

No measurable performance impact in production code. The interpreter or compiler resolves named arguments at runtime, but this overhead is negligible compared to actual function execution time. Clarity and maintainability benefits far outweigh any theoretical performance cost.

How do I handle named arguments in function wrappers or decorators?

In Python, use **kwargs to forward named arguments: wrapper(*args, **kwargs). In PHP, use variadic parameters and argument unpacking: function wrapper(...$args) then originalFunc(...$args). This preserves named arguments when passed through intermediary functions.

Can I mix positional and named arguments?

Yes, but positional arguments must come first. In both Python and PHP, you can call func(posArg1, posArg2, namedArg: value). However, once you use a named argument, all subsequent arguments must be named. This prevents ambiguity in parameter mapping.

What about backward compatibility with older PHP or Python versions?

Python supported named arguments since Python 2. PHP added named arguments in PHP 8.0. For older PHP versions, use associative arrays as a single parameter: function createUser(array $options) and access values like $options['email']. This achieves similar clarity while maintaining compatibility.

Get secure now

Secure your code, cloud, and runtime in one central system.
Find and fix vulnerabilities fast automatically.

No credit card required | Scan results in 32secs.