在PHP中测试可选参数

Dan*_*ugg 17 php pass-by-reference default-value optional-parameters

我在类之间有一些"setter"方法,为方便起见,我添加了一个可选参数$previous,它通过引用获取参数,并在用新值替换之前用现有值填充它.例如:

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

这很好用; 但是在某些情况下,相应的"getter"方法有点过程密集,无条件运行它是一种浪费.我想我可以测试:

if(null !== $previous)
{
    $previous = $this->get_value($key);
}
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

或者,一行:

if(array_key_exists(2, func_get_args()))
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢方法体依赖于参数索引(当它看起来应该是不必要的时候)有没有更清晰的方法来实现我在这里之后的东西?


我试过了:

if(isset($previous)){}

if(!empty($previous)){}

if(null !== $previous){}
Run Code Online (Sandbox Code Playgroud)

都没有工作.

迄今可能的解决方案:

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()){}
Run Code Online (Sandbox Code Playgroud)

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

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

function foo($bar = _NOPARAM)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

@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()
    -> ...
Run Code Online (Sandbox Code Playgroud)

代替:

$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();
    -> ...
Run Code Online (Sandbox Code Playgroud)

cat*_*try 3

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

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;
}
Run Code Online (Sandbox Code Playgroud)

用例示例:

$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()
    -> ...
Run Code Online (Sandbox Code Playgroud)

为什么要使用另一个函数?

该解决方案有几个优点:

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

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

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