Skip to Content
Course content

12: Default and Variadic Arguments

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I've noticed a recurring pattern when I'm reviewing code from developers moving into PHP: they often treat default arguments as "optional flags" that can be tossed anywhere in the function signature. You might think that as long as a variable has a default value, PHP will just "skip" it if you don't provide one and move on to the next required argument. It seems intuitive, but it's a trap.

The myth that default arguments can be placed anywhere

Let's look at why this doesn't work. Imagine you're building a notification system and you want a default subject line, but the recipient's email is mandatory. You might try writing it like this:

function sendNotification($subject = "System Alert", $email) {
    echo "Sending '$subject' to $email";
}

// You try to call it by only providing the email
sendNotification("dev@example.com"); 

You're probably expecting PHP to see that you only passed one string, realize it doesn't match the default subject, and assign it to $email. But that's not how it works. PHP assigns arguments positionally. In the example above, "dev@example.com" is assigned to $subject because it's the first argument. Then, PHP realizes $email is missing and throws an ArgumentCountError.

Putting your defaults at the end of the line

To make this actually work, you have to follow one simple rule: optional parameters must come after all required parameters. I usually tell my juniors to think of it as a "mandatory first" queue. If you put the required arguments first, the function knows exactly what it needs to survive before it starts looking at the "nice-to-have" defaults.

function sendNotification($email, $subject = "System Alert") {
    echo "Sending '$subject' to $email";
}

// Now this works exactly as you'd expect
sendNotification("dev@example.com"); 
// Output: Sending 'System Alert' to dev@example.com

Now, what happens if you have five or six optional settings? Writing five different default values starts to feel clunky. That's where variadic arguments come in.

Handling an unknown number of inputs with the splat operator

Sometimes you don't know how many arguments a user will pass. Maybe you're writing a function to calculate a total, or a logger that accepts any number of messages. Instead of forcing the user to wrap everything in an array, you can use the ... operator (which we often call the "splat operator").

When you prefix a parameter with ..., PHP gathers all remaining arguments passed to the function and bundles them into a single array. It's a much cleaner API for whoever is using your function.

function calculateTotal($taxRate, ...$prices) {
    $subtotal = array_sum($prices);
    return $subtotal + ($subtotal * $taxRate);
}

// I can pass two prices...
echo calculateTotal(0.05, 10.00, 20.00); // 31.5

// ...or twenty prices. The function doesn't care.
echo calculateTotal(0.05, 5.00, 1.50, 10.00, 2.00, 45.00); 

One important detail: a variadic parameter must be the very last parameter in your function signature. You can't have a default argument or a required argument coming after the splat, because once PHP starts gathering arguments into that array, there's nothing left for the subsequent variables to grab.

  • Required arguments first.
  • Default arguments second.
  • Variadic arguments (the splat) absolute last.



📋 Practical Task

Building a Flexible Invoice Total Calculator

You are tasked with creating a function called generateInvoiceTotal. This function needs to handle a variety of scenarios for a small business owner.

Requirements:

  • The first argument must be the $customerName (required).
  • The second argument should be a $discount (default to 0).
  • The final argument should be a variadic list of $items (each item is a numeric price).

The function should:

  1. Sum all the $items.
  2. Subtract the $discount amount from that sum.
  3. Return a string in this exact format: "Invoice for [Customer]: $[Total]".

Test your code with these two cases:

echo generateInvoiceTotal("Alice", 5, 10, 20, 30); 
// Expected: Invoice for Alice: $55 (Sum is 60, minus 5 discount)

echo generateInvoiceTotal("Bob", 0, 100, 200); 
// Expected: Invoice for Bob: $300 (Sum is 300, minus 0 discount)
Rating
0 0

There are no comments for now.

to be the first to leave a comment.