虽然这是一个旧的帖子,但可变函数和数组展开可以(在一定程度上)用于实现类型化数组提示,至少在PHP7中可以实现(我没有测试早期版本)。
示例:
class Foo {
public function test(){
echo "foo";
}
};
class Bar extends Foo {
public function test(){
echo "bar";
}
}
function test(Foo ...$params){
foreach($params as $param){
$param->test();
}
}
$f = new Foo();
$b = new Bar();
$arrayOfFoo = [$f,$b];
test(...$arrayOfFoo);
局限性:
从技术上讲,这不是一个解决方案,因为你实际上没有传递一个类型化数组。相反,你使用数组展开运算符1(在函数调用中的“...”)将数组转换为参数列表,每个参数都必须是变参声明2中指定的类型(它还使用省略号)。
函数调用中的“...”是绝对必要的(鉴于上述情况,这并不令人惊讶)。试图调用
test($arrayOfFoo)
在上述示例的情况下,使用数组作为参数将导致类型错误,因为编译器期望foo的参数,而不是数组。请参见下面的内容,了解传递给定类型的数组的一种方法,虽然有点巧妙,但仍保留了某些类型提示。
可变函数只能有一个可变参数,并且它必须是最后一个参数(否则编译器如何确定可变参数何时结束并开始下一个参数),这意味着您不能声明类似以下方式的函数:
function test(Foo ...$foos, Bar ...$bars){
//...
}
或者
function test(Foo ...$foos, Bar $bar){
}
仅稍微好于逐个检查元素的替代方案:
以下步骤实际上比仅检查每个元素类型要好,因为它保证了函数体中使用的参数具有正确的类型,而不会使函数充满类型检查,并且它会抛出通常的类型异常。
考虑:
function alt(Array $foos){
return (function(Foo ...$fooParams){
foreach($fooParams as $foo){
$foo->test();
}
})(...$foos);
}
这个想法是定义并返回一个立即调用的闭包,该闭包会为您处理所有可变参数和解包操作。(可以进一步扩展原则,定义一个生成此结构函数的高阶函数,以减少样板代码)。在上面的示例中:
alt($arrayOfFoo) // also outputs "foobar"
这种方法存在以下问题:
(1) 对于经验不足的开发人员,可能不太清楚。
(2) 它可能会产生一些性能开销。
(3) 与仅内部检查数组元素类似,它把类型检查视为实现细节,因此必须检查函数声明(或享受类型异常)才能意识到只有特定类型的数组才是有效的参数。在接口或抽象函数中,无法编码完整的类型提示;所有人能做的就是注释说期望上述类型的实现(或类似的实现)。
注释
[1]. 简而言之:数组解包渲染等效
example_function($a,$b,$c)
和
example_function(...[$a,$b,$c])
[2]. 简而言之:形如
可变参数函数。
function example_function(Foo ...$bar){
}
可以通过以下任何一种方式有效地调用:
example_function();
example_function(new Foo());
example_function(new Foo(), new Foo());
example_function(new Foo(), new Foo(), new Foo());
//and so on
function getFoo($f) { ... }
即可。因此,如果您想要一个专门处理数组的函数,只需创建一个新函数function getFooArray($f) { ... }
即可。 - sjagrfunction getFoos(Array $f)
,它解析数组并将每个$f[$i]
传递给function getFoo(Foo $g)
。 - Frank Conryfunction foo(Abc ...$args) { } foo(...$arr);
,具体内容请参考此处。 - Shahid