Athari
Athari

Reputation: 34285

Special "undefined" value for default value of argument in PHP function

I need an optional argument that accepts any value (including null and false), but still has "unspecified" state to allow a different "default" behavior. Is there any technique in PHP which allows imitating "undefined" value?


I want to add append method to YaLinqo, my port of .NET's LINQ. Currently the code looks like this:

public function append ($value, $key = null)
{
    return new self(function () use ($value, $key) {
        foreach ($this as $k => $v)
            yield $k => $v;
        if ($key !== null)
            yield $key => $value;
        else
            yield $value;
    });
}

The problem is, if somebody wants to use null as a key, they won't be able to do it, as it's a special "undefined" value currently, which will cause yielding using automatic sequental integer. In PHP, iterator containing sequence [ null => null, null => null ] is perfectly valid and user should be able to produce it using append.

I'm considering adding const UNDEFINED = '{YaLinqo.Utils.Undefined}':

const UNDEFINED = '{YaLinqo.Utils.Undefined}';

public function append ($value, $key = Utils::UNDEFINED)
{
    return new self(function () use ($value, $key) {
        foreach ($this as $k => $v)
            yield $k => $v;
        if ($key !== Utils::UNDEFINED)
            yield $key => $value;
        else
            yield $value;
    });
}

Is this a valid approach? Is there a cleaner way?

Upvotes: 3

Views: 1189

Answers (2)

Aleksander Wons
Aleksander Wons

Reputation: 3967

You could use func_get_args() to achieve what you want. Take a look at the following example:

function test($value, $key = null) {
    var_dump(func_get_args());
}

test(1);
test(2, null);

And here is the output:

array(1) {
  [0]=>
  int(1)
}
array(2) {
  [0]=>
  int(2)
  [1]=>
  NULL
}

As you can see the argument list only contains passed in arguments and not defined arguments. If you want to know if someone explicitly passed null you can do:

$args = func_get_args();
if (isset($args[1]) && $args[1] === null) {}

Or if you want to know the argument was not passed you can do:

$args = func_get_args();
if (!isset($args[1])) {}

Upvotes: 4

Agnius Vasiliauskas
Agnius Vasiliauskas

Reputation: 11267

No simple way to achieve this. In your case user still can define $key with {YaLinqo.Utils.Undefined} value and in that case incorrect code branch will execute. I can only think of one solution - we can analyze call stack frames to be sure if user passed some argument or not. Like so :

<?php

function test() {
 func(1, null);
 func(1); 
}

function func ($x, $y = null) { 
  $stack = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 1);
  if (count($stack[0]['args']) == 2)
    echo "\$y argument is defined\n";
  else
    echo "\$y argument is UNDEFINED\n";
}

test();

?>

Upvotes: 0

Related Questions