在 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);
}
但这不起作用,因为作为 $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;
}
或者,单行:
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();
-> ...
I have a few "setter" methods across classes, and for convenience I've added an optional parameter $previous
, which takes an argument by reference and populates it with the existing value before replacing it with the new one. For example:
public function set_value($key, $value, &$previous = null)
{
$previous = $this->get_value($key);
$this->_values[$key] = $value;
return $this;
}
This works fine; however in some circumstances, the corresponding "getter" method is a bit process intensive, and running it unconditionally is a waste. I figured I could test:
if(null !== $previous)
{
$previous = $this->get_value($key);
}
This doesn't work though, as often the variable passed as the argument for $previous
hasn't been previously defined in it's scope, and defaults to null anyway. The only solution I've hacked out is:
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;
}
Or, to one-line it:
if(array_key_exists(2, func_get_args()))
{
// ...
}
I don't like the method body being reliant on the argument indices (when it seems it should be unnecessary) Is there a cleaner way to achieve what I'm after here?
I've tried:
if(isset($previous)){}
if(!empty($previous)){}
if(null !== $previous){}
Neither work.
Possible solutions thus far:
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 -- So, something in the area of:
define('_NOPARAM', '_NOPARAM' . hash('sha4096', microtime()));
function foo($bar = _NOPARAM)
{
// ...
}
@hoppa -- Use case:
$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()
-> ...
Instead of:
$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();
-> ...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
可能不是您想要解决问题的方式(以某种方式测试可选参数),但这就是我实现它的方式:
用例示例:
为什么使用另一个函数?
这个解决方案有一些优点:
func_num_args
或其他一些“元”的开销“函数编辑:拼写错误 代码。
编辑2:删除了 &$previous set_get_value() 函数的默认值(感谢 draevor)
possibly not how you wanted to solve your problem (testing somehow optional arguments), but this is how I would implement it:
Use case example:
Why use another function?
This solution has a few advantages:
func_num_args
, or some other "meta" functionEDIT: typo in code.
EDIT 2: removed default value of &$previous set_get_value() function (thanks to draevor)
摘自上面的评论/讨论:
为了检查参数是否已传递,您有 2 个选项 - 根据值检查参数的值(就像您对 null 所做的那样)或检查参数的数量。
如果您选择第一个选项,则没有任何值不能从函数外部传递,因此总是有可能出现误报(与现在使用 null 时发生的情况相同)。 DaveRandom 的随机字符串示例对于大多数情况来说应该足够了,但我认为它有点矫枉过正。
我认为第二个选项是最干净的(快速、可读等)。作为对 func_get_args 所做的一个小改进,我将使用 func_num_args - 这样您将检查传递参数的数量,而不是参数指数。
Extracted from the comments / discussion above:
In order to check whether the argument was passed you have 2 options - check the value of the argument against a value (as you've done with null) or check the number of arguments.
If you go with the first option, there's no value that cannot be passed from outside the function, so there will always be a chance for false positives (the same thing that's happening now with null). DaveRandom's example with a random string should be enough for most cases though, but I see it as overkill.
I think the second option is the most clean (fast, readable, etc). As a small improvement over what you've already done with
func_get_args
, I'd usefunc_num_args
- this way you'll be checking the number of passed arguments, not the argument indices.