Some PHP function code receives a $function
argument and its argument as a variable. It is then called using $function(...$args);
I wonder how i should test the variable so as to be sure i can apply the spread operator onto it. As for now i use this code :
if (!$args) {
return $function();
}
elseif (is_array($args) or ($args instanceof \Traversable)) {
return $function(... $args);
}
else {
return 'Error';
}
Is this ok ?
The PHP Manual states that you only need to check if the data type is iterable.
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()
is available from PHP7.1.
An empty array can still be spread, but this is equivalent to pass no arguments into your $function
.
So, you can simplify the check to:
if (is_iterable($data) {
return $function(...$data);
}
return "Data is not iterable";
BUT, it is not enough to check is_iterable()
. From PHP8 (it was proposed for PHP8.1, 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.
In other words, if the function receiving this data is not designed to accommodate the spread-able data, then the script will fire a Fatal Error.
Code: (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));
Output (on 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
This proves that you must not only check the type of the data being passed in, you must also acknowledge the context of what the called function does (specifically, what it can receive). If you can 100% guarantee that arrays will suit the function signature and/or that named parameters will never be used in function declarations, then you may be able to confidently go forward. Otherwise, there will remain the possibility of exposing your script to bugs. I am not sure if the toil involved in pre-checking the relationship of the data to the function call will be worth your intended gain in flexibility.