PHP可迭代到数组或Traversable

时间:2017-06-16 11:18:49

标签: php arrays iterator php-7 php-7.1

我很高兴PHP 7.1引入了the iterable pseudo-type

现在虽然只是在循环这个类型的参数时很好,但是当你需要将它传递给仅接受array或仅{{1}的PHP函数时,我不清楚该怎么做}}。例如,如果您想要执行array_diff,而Traversableiterable,则会获得Traversable。相反,如果您调用带有Iterator的函数,如果arrayiterable,则会出错。

是否有类似array(NOT:iterable_to_array)和iterator_to_array的内容?

我正在寻找一种解决方案,避免我的函数中的条件只是为了处理这种差异,而这并不依赖于我定义自己的全局函数。

使用PHP 7.1

7 个答案:

答案 0 :(得分:7)

不确定这是你在寻找什么,但这是最简单的方法。

$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()会很好,但因为它是一种语言结构有点特殊。它也不会保留关联数组中的键。

答案 1 :(得分:2)

  

是否有像iterable_to_array和iterable_to_traversable

这样的东西

只需将这些内容添加到您的项目中,它们就不会占用大量空间并为您提供所需的确切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;
}

答案 2 :(得分:1)

您可以先使用iterator_to_array将变量转换为Traversable

$array = iterator_to_array((function() use ($iterable) {yield from $iterable;})());

转换方法取自this question下的评论。

这是working demo

答案 3 :(得分:1)

术语容易混合

  • 可流通
    • 迭代器(我将其视为一种具体类型,例如用户定义的类A)
    • IteratorAggregate
  • 可迭代(接受伪类型数组可遍历
  • array(这是一个具体类型,在需要Iterator类型的情况下,不能与Iterator交换)
  • arrayIterator(可用于将数组转换为迭代器)

因此,这就是为什么如果函数A(iterable $ a){},则它接受数组的参数或 traversable 的实例(Iterator,IteratorAggregate均被接受,因为很明显这两个类都实现了 Traversable 。在我的测试中,通过ArrayIterator也是可以的)。

如果为参数指定了Iterator类型,则传入数组将导致TypeError。

答案 4 :(得分:0)

对于“可迭代数组”情况,似乎没有可以进行的单个函数调用,您要么需要在代码中使用条件函数,要么像这样定义自己的函数:

function iterable_to_array( iterable $iterable ): array {
    if ( is_array( $iterable ) ) {
        return $iterable;
    }
    return iterator_to_array( $iterable );
}

对于“ Iterable to Iterator”而言,情况要复杂得多。使用Traversable可以很容易地将数组转换为ArrayIteratorIterator个实例可以照原样返回。剩下的Traversable实例不是Iterator。乍一看,您似乎可以使用IteratorIterator来使用Traversable。但是,给该类返回一个IteratorAggregate的{​​{1}}时,该类存在错误,无法正常工作。

尽管我创建了一个包含两个转换函数的小型库,但是解决此问题的方法太长了,无法在此处发布:

  • 函数iterable_to_iterator(iterable $ iterable):迭代器
  • 函数iterable_to_array(iterable $ iterable):数组

请参见https://github.com/wmde/iterable-functions

答案 5 :(得分:0)

可以这样:

$array = $iterable instanceof \Traversable ? iterator_to_array($iterable) : (array)$iterable;

答案 6 :(得分:0)

对于 php >= 7.4,这开箱即用:

$array = array(...$iterable);

https://3v4l.org/L3JNH

编辑:仅当迭代不包含字符串键时才有效