PHP 可迭代到数组或可遍历
PHP iterable to array or Traversable
我很高兴 PHP 7.1 推出 the iterable pseudo-type。
现在虽然这在循环这种类型的参数时很棒,但我不清楚当您需要将它传递给仅接受 array
的 PHP 函数时该怎么做或者只是一个 Traversable
。例如,如果你想做一个 array_diff,而你的 iterable
是一个 Traversable
,你将得到一个 array
。相反,如果您调用一个带有迭代器的函数,如果 iterable
是 array
.
,您将收到错误消息
是否有类似 iterable_to_array
(不是:iterator_to_array
)和 iterable_to_traversable
的东西?
我正在寻找一种解决方案,避免在我的函数中使用条件语句来解决这种差异,而不依赖于我定义自己的全局函数。
使用 PHP 7.1
不确定这就是您要搜索的内容,但这是最短的方法。
$array = [];
array_push ($array, ...$iterable);
我不太确定它为什么有效。只是我发现你的问题很有趣,我开始摆弄 PHP
完整示例:
<?php
function some_array(): iterable {
return [1, 2, 3];
}
function some_generator(): iterable {
yield 1;
yield 2;
yield 3;
}
function foo(iterable $iterable) {
$array = [];
array_push ($array, ...$iterable);
var_dump($array);
}
foo(some_array());
foo(some_generator());
如果能和函数array()
一起使用就好了,但是因为它是一种语言结构,所以有点特殊。它也不保留关联数组中的键。
Is there something like iterable_to_array and iterable_to_traversable
只需将这些添加到项目的某处,它们不会占用很多 space 并为您提供所需的确切 API。
function iterable_to_array(iterable $it): array {
if (is_array($it)) return $it;
$ret = [];
array_push($ret, ...$it);
return $ret;
}
function iterable_to_traversable(iterable $it): Traversable {
yield from $it;
}
你可以先用iterator_to_array
converting your variable to Traversable
:
$array = iterator_to_array((function() use ($iterable) {yield from $iterable;})());
转换方法取自this question下的评论。
这里是working demo。
术语很容易混合
- 可遍历
- 迭代器(我把它看成一个具体的类型,就像用户定义的classA)
- 迭代器聚合
- iterable(这是一个伪类型,array或者traversable都可以接受)
- array(这是一个具体类型,在需要 Iterator 类型的上下文中它不能与 Iterator 交换)
- arrayIterator(可用于将数组转换为迭代器)
所以,这就是为什么如果函数 A(iterable $a){},那么它接受数组或实例的参数 traversable(Iterator、IteratorAggregate 都被接受,因为它是很明显,这两个 classes 实现了 Traversable。在我的测试中,传递 ArrayIterator 也有效。
如果参数指定了Iterator类型,传入数组会导致TypeError。
对于 "iterable to array" 情况,您似乎无法进行单一函数调用,您需要在代码中使用条件语句或像这样定义自己的函数:
function iterable_to_array( iterable $iterable ): array {
if ( is_array( $iterable ) ) {
return $iterable;
}
return iterator_to_array( $iterable );
}
对于 "iterable to Iterator" 情况,事情要复杂得多。使用 ArrayIterator
可以轻松地将数组转换为 Traversable
。 Iterator
个实例可以按原样返回。剩下 Traversable
个不是 Iterator
的实例。乍一看,您似乎可以使用 IteratorIterator
,它需要一个 Traversable
。但是 class 有漏洞并且在给它一个 IteratorAggregate
一个 returns 一个 Generator
.
时不能正常工作
虽然我创建了一个包含两个转换函数的迷你库,但此问题的解决方案太长 post:
- 函数iterable_to_iterator(可迭代的$iterable):迭代器
- 函数iterable_to_array(可迭代的$iterable):数组
可以这样做:
$array = $iterable instanceof \Traversable ? iterator_to_array($iterable) : (array)$iterable;
对于 php >= 7.4,开箱即用:
$array = array(...$iterable);
编辑: 仅在可迭代对象不包含字符串键时有效
我想扩展 Edwin Rodríguez 给出的答案,不幸的是我还没有足够的代表post对此作为评论。
比初始化数组然后使用 array_push 将迭代器内容加载到其中稍微简单一些,您可以简单地(对于某些用例)使用数组括号并组合展开;
$array = [...$iterable];
当您想要将干净的、可内联的语法传递给数组函数时,这非常方便。
编辑:我现在意识到这实际上与 Michael Petri 给出的答案相同,但是对于 php>=7.4 我认为短数组语法是首选。除非您需要遵循另有说明的特定风格指南
我很高兴 PHP 7.1 推出 the iterable pseudo-type。
现在虽然这在循环这种类型的参数时很棒,但我不清楚当您需要将它传递给仅接受 array
的 PHP 函数时该怎么做或者只是一个 Traversable
。例如,如果你想做一个 array_diff,而你的 iterable
是一个 Traversable
,你将得到一个 array
。相反,如果您调用一个带有迭代器的函数,如果 iterable
是 array
.
是否有类似 iterable_to_array
(不是:iterator_to_array
)和 iterable_to_traversable
的东西?
我正在寻找一种解决方案,避免在我的函数中使用条件语句来解决这种差异,而不依赖于我定义自己的全局函数。
使用 PHP 7.1
不确定这就是您要搜索的内容,但这是最短的方法。
$array = [];
array_push ($array, ...$iterable);
我不太确定它为什么有效。只是我发现你的问题很有趣,我开始摆弄 PHP
完整示例:
<?php
function some_array(): iterable {
return [1, 2, 3];
}
function some_generator(): iterable {
yield 1;
yield 2;
yield 3;
}
function foo(iterable $iterable) {
$array = [];
array_push ($array, ...$iterable);
var_dump($array);
}
foo(some_array());
foo(some_generator());
如果能和函数array()
一起使用就好了,但是因为它是一种语言结构,所以有点特殊。它也不保留关联数组中的键。
Is there something like iterable_to_array and iterable_to_traversable
只需将这些添加到项目的某处,它们不会占用很多 space 并为您提供所需的确切 API。
function iterable_to_array(iterable $it): array {
if (is_array($it)) return $it;
$ret = [];
array_push($ret, ...$it);
return $ret;
}
function iterable_to_traversable(iterable $it): Traversable {
yield from $it;
}
你可以先用iterator_to_array
converting your variable to Traversable
:
$array = iterator_to_array((function() use ($iterable) {yield from $iterable;})());
转换方法取自this question下的评论。
这里是working demo。
术语很容易混合
- 可遍历
- 迭代器(我把它看成一个具体的类型,就像用户定义的classA)
- 迭代器聚合
- iterable(这是一个伪类型,array或者traversable都可以接受)
- array(这是一个具体类型,在需要 Iterator 类型的上下文中它不能与 Iterator 交换)
- arrayIterator(可用于将数组转换为迭代器)
所以,这就是为什么如果函数 A(iterable $a){},那么它接受数组或实例的参数 traversable(Iterator、IteratorAggregate 都被接受,因为它是很明显,这两个 classes 实现了 Traversable。在我的测试中,传递 ArrayIterator 也有效。
如果参数指定了Iterator类型,传入数组会导致TypeError。
对于 "iterable to array" 情况,您似乎无法进行单一函数调用,您需要在代码中使用条件语句或像这样定义自己的函数:
function iterable_to_array( iterable $iterable ): array {
if ( is_array( $iterable ) ) {
return $iterable;
}
return iterator_to_array( $iterable );
}
对于 "iterable to Iterator" 情况,事情要复杂得多。使用 ArrayIterator
可以轻松地将数组转换为 Traversable
。 Iterator
个实例可以按原样返回。剩下 Traversable
个不是 Iterator
的实例。乍一看,您似乎可以使用 IteratorIterator
,它需要一个 Traversable
。但是 class 有漏洞并且在给它一个 IteratorAggregate
一个 returns 一个 Generator
.
虽然我创建了一个包含两个转换函数的迷你库,但此问题的解决方案太长 post:
- 函数iterable_to_iterator(可迭代的$iterable):迭代器
- 函数iterable_to_array(可迭代的$iterable):数组
可以这样做:
$array = $iterable instanceof \Traversable ? iterator_to_array($iterable) : (array)$iterable;
对于 php >= 7.4,开箱即用:
$array = array(...$iterable);
编辑: 仅在可迭代对象不包含字符串键时有效
我想扩展 Edwin Rodríguez 给出的答案,不幸的是我还没有足够的代表post对此作为评论。
比初始化数组然后使用 array_push 将迭代器内容加载到其中稍微简单一些,您可以简单地(对于某些用例)使用数组括号并组合展开;
$array = [...$iterable];
当您想要将干净的、可内联的语法传递给数组函数时,这非常方便。
编辑:我现在意识到这实际上与 Michael Petri 给出的答案相同,但是对于 php>=7.4 我认为短数组语法是首选。除非您需要遵循另有说明的特定风格指南