在 PHP 中测试可选参数

我有一些跨类的“setter”方法,为了方便起见,我添加了一个可选参数,该参数通过引用获取参数并用现有值填充它,然后再用新值替换它。例如:$previous

public function set_value($key, $value, &$previous = null)
{
    $previous = $this->get_value($key);
    $this->_values[$key] = $value;
    return $this;
}

这工作正常;然而,在某些情况下,相应的“getter”方法有点过程密集,无条件运行它是一种浪费。我想我可以测试:

if(null !== $previous)
{
    $previous = $this->get_value($key);
}

但是,这不起作用,因为作为 参数传递的变量通常以前未在其作用域中定义,并且无论如何都默认为 null。我破解的唯一解决方案是:$previous

public function set_value($key, $value, &$previous = null)
{
    $args = func_get_args();
    if(isset($args[2])
    {
        $previous = $this->get_value($key);
    }
    $this->_values[$key] = $value;
    return $this;
}

或者,用一行它:

if(array_key_exists(2, func_get_args()))
{
    // ...
}

我不喜欢方法体依赖于参数索引(当它似乎应该是不必要的)有没有一种更干净的方式来实现我在这里所追求的目标?


我试过了:

if(isset($previous)){}

if(!empty($previous)){}

if(null !== $previous){}

两者都不起作用。

到目前为止可能的解决方案:

if(func_num_args() == $num_params){}

if(array_key_exists($param_index, func_get_args())){}

// 5.4
if(isset(func_get_args()[$param_index])){}

// 5.4
if(func_num_args() == (new \ReflectionMethod(__CLASS__, __FUNCTION__))
    ->getNumberOfParameters()){}

@DaveRandom -- 所以,在以下领域:

define('_NOPARAM', '_NOPARAM' . hash('sha4096', microtime()));

function foo($bar = _NOPARAM)
{
    // ...
}

@hoppa -- 使用案例:

$obj->set_something('some_key', $some_value, $previous) // set
    ->do_something_that_uses_some_key()
    ->set_something('some_key', $previous) // and reset
    ->do_something_that_uses_some_key()
    -> ...

而不是:

$previous = $obj->get_something('some_key'); // get
$obj->set_something('some_key', $some_value) // set
    ->do_something_that_uses_some_key();
    ->set_something($previous) // and reset
    ->do_something_that_uses_some_key();
    -> ...

答案 1

可能不是你想如何解决你的问题(以某种方式测试可选参数),但这就是我实现它的方式:

public function set_value($key, $value)
{
    $this->_values[$key] = $value;
    return $this;
}
public function set_get_value($key, $value, &$previous)
{
    $previous = $this->get_value($key);
    $this->_values[$key] = $value;
    return $this;
}

用例示例:

$obj->set_get_something('some_key', $some_value, $previous) // set AND get
    ->do_something_that_uses_some_key()
    ->set_something('some_key', $previous) // and reset
    ->do_something_that_uses_some_key()
    -> ...

为什么要使用其他函数?

此解决方案具有以下几个优点:

  1. 名称更明确,其他编码人员的混淆更少
  2. 无隐藏的副作用
  3. 解决了(未定义的)变量已经具有值的问题
  4. 没有调用的开销,或其他一些“元”功能func_num_args

编辑:代码中的拼写错误。

编辑2:删除了&$previous set_get_value()函数的默认值(感谢draevor)


答案 2

摘自上面的评论/讨论:

为了检查参数是否被传递,您有2个选项 - 根据值检查参数的值(就像您对null所做的那样)或检查参数的数量。

如果使用第一个选项,则没有无法从函数外部传递的值,因此始终存在误报的机会(现在在 null 中发生的情况相同)。DaveRandom用随机字符串的例子在大多数情况下应该足够了,但我认为这有点过分了。

我认为第二个选项是最干净的(快速,可读等)。作为对您已经完成的工作的一个小小的改进,我会使用 - 这样您将检查传递的参数的数量,而不是参数索引。func_get_argsfunc_num_args


推荐