How to tell if optional parameter in PHP method/function was set or not?
Asked Answered
E

3

15

Assume I have a method/function with the following signature:

foo($bar = 0)

Inside foo, how do I tell if $bar was set or not? isset will alway return a TRUE since $bar is assigned 0 in the event nothing is passed to foo.

Checking for 0 is not an option. I need to know the difference between the parameter explicitly being set to 0 or defaulting to 0.

Eigenvalue answered 12/8, 2010 at 20:40 Comment(3)
That's a really kludgey way for a function to behave. f(0) should produce the same result, regardless of the "source" of the argument 0.Sloe
Not if you are creating a polymorphic method that does one thing if the parameter is set and another thing if the parameter is not set.Eigenvalue
Frank, some built in functions do this, in my case I needed to wrap substr, and when I passed the wrappers $length default argument of null to substr, I got nothing back, as substr interprets that as 0 length. Yes, it is insanely kludgey, I've come to expect nothing better of PHP.Peru
N
15

Simply use func_num_args() to specifically check for how many arguments were passed in.

<?php
function foo($bar = 0)
{
    echo "\nNumber of arguments: " . func_num_args();
}

  // Outputs "Number of arguments: 1"
foo(0);

  // Outputs "Number of arguments: 0"
foo();
?>    

Live example

Newhouse answered 12/8, 2010 at 20:43 Comment(0)
A
9

You can use func_get_args. Example:

function foo($optional=null) {
    if (count(func_get_args()) > 0)
        echo "optional given\n";
    else
        echo "optional not given\n";
}

foo(); //optional not given
foo(null); //optional given

Note that the convention used for internal PHP functions is to always give optional arguments a default value and to have them have the same behavior when both argument is not given and its default value is explicitly given. If you ever find otherwise, file a bug report. This let's you do stuff like this without ifs:

function strpos_wrap($haystack, $needle, $offset = 0) {
    return strpos($haystack, $needle, $offset);
}

This convention is more enforced is userland, as the difficulty that led you to this question has shown you. If the convention doesn't suit your needs, at least reconsider your approach. The purpose of func_num_args/func_get_args is mainly to allow variable argument functions.

Admonition answered 12/8, 2010 at 20:48 Comment(1)
This wasn't an issue when this was asked, but these days, how would this work if arguments are passed as named arguments?Cutting
O
0

If your function/method signature has only one optional parameter, func_num_args() or func_get_args() can be checked with confidence inside the function body.

Code: (Demo)

function foo($a = null) {
    echo json_encode(['func_num_args' => func_num_args(), 'func_get_args' => func_get_args()]);
    echo "\n";
}

echo "no param: " , foo();

echo "a as null: " , foo(a: null);

Output:

no param: {"func_num_args":0,"func_get_args":[]}
a as null: {"func_num_args":1,"func_get_args":[null]}

Bear in mind that if you have multiple parameters in your function/method signature, func_ functions lack the necessary precision to express exactly which parameter was passed-in versus assigned by default value.

func_get_args() produces an indexed array and func_num_args() produces an integer -- neither which is not helpful. Because "named parameters" allow data to be passed-in in any order, there can be no way of knowing which optional parameter was omitted. The best that can be achieved is determining that either all optional parameters were passed-in or none were passed-in.

Code: (Demo):

function foo($a = null, $b = null, $c = null, $d = null) {
    echo json_encode(['func_num_args' => func_num_args(), 'func_get_args' => func_get_args()]);
    echo "\n";
}

echo "no params: " , foo();

echo "a as null: " , foo(a: null);

echo "b as null: " , foo(b: null);

echo "c as null: " , foo(c: null);

echo "d as null: " , foo(d: null);

echo "d & a as null: " , foo(d: null, a: null);

Output:

no params: {"func_num_args":0,"func_get_args":[]}
a as null: {"func_num_args":1,"func_get_args":[null]}
b as null: {"func_num_args":2,"func_get_args":[null,null]}
c as null: {"func_num_args":3,"func_get_args":[null,null,null]}
d as null: {"func_num_args":4,"func_get_args":[null,null,null,null]}
d & a as null: {"func_num_args":4,"func_get_args":[null,null,null,null]}
Orgel answered 17/7 at 22:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.