如何检测变量是否可以与扩展运算符一起使用

How detect if variable can be used with spread operator

一些 PHP 函数代码接收一个 $function 参数并将其参数作为变量。然后使用 $function(...$args);

调用它

我想知道我应该如何测试该变量以确保我可以将扩展运算符应用于它。至于现在我使用这个代码:

if (!$args) {
  return $function();
}
elseif (is_array($args) or ($args instanceof \Traversable)) {
  return $function(... $args);
}
else {
  return 'Error';
}

这样可以吗?

PHP Manual表示只需要检查数据类型是否可迭代

Verify that the contents of a variable is accepted by the iterable pseudo-type, i.e. that it is either an array or an object implementing Traversable

is_iterable() 可从 PHP7.1.

获得

一个空数组仍然可以传播,但这相当于不向你的$function传递任何参数。

因此,您可以将检查简化为:

if (is_iterable($data) {
    return $function(...$data);
}
return "Data is not iterable";

但是,检查 is_iterable() 还不够。从 PHP8 (, but is available in 8.0 -- see my demo link below), arrays with non-numeric keys can be spread. In PHP8, named parameters were introduced and this means that the spread operator can be used to unpack associative arrays with keys that match a function's argument signature.
换句话说,如果接收此数据的函数未设计为容纳 spread-able 数据,则脚本将触发致命错误。

代码:(Demo)

function zeroOneTwo($one, $two, $three) {
    return [$one, $two, $three];
}

function abc($b, $c, $a) {
    return [$a, $b, $c];
}

function spread(...$data) {
    return $data;
}

$numericKeyedArray = [4,5,6];
var_export(abc(...$numericKeyedArray));
echo "\n---\n";
var_export(spread(...$numericKeyedArray));
echo "\n===\n";
var_export(zeroOneTwo(...$numericKeyedArray));
echo "\n===\n";

$nonNumericKeyedArray = ['c' => 'sea', 'a' => 'A', 'b' => 'bee'];
echo "\n---\n";
var_export(abc(...$nonNumericKeyedArray));
echo "\n===\n";
var_export(spread(...$nonNumericKeyedArray));
echo "\n===\n";
var_export(zeroOneTwo(...$nonNumericKeyedArray));

输出(PHP8):

array (
  0 => 6,
  1 => 4,
  2 => 5,
)
---
array (
  0 => 4,
  1 => 5,
  2 => 6,
)
===
array (
  0 => 4,
  1 => 5,
  2 => 6,
)
===

---
array (
  0 => 'A',
  1 => 'bee',
  2 => 'sea',
)
===
array (
  'c' => 'sea',
  'a' => 'A',
  'b' => 'bee',
)
===

Fatal error: Uncaught Error: Unknown named parameter $c

这证明您不仅要检查传入数据的类型,还必须了解被调用函数的作用(具体来说,它可以接收什么)的上下文。如果你能 100% 保证数组适合函数签名 and/or 命名参数永远不会在函数声明中使用,那么你就可以自信地继续前进。否则,您的脚本仍有可能出现错误。我不确定 pre-checking 数据与函数调用的关系所涉及的辛劳是否值得您在灵活性方面获得预期的收益。