PHP, итерируемый в массив или проходимый


Я очень рад, что PHP 7.1 представил повторяющийся псевдотип.

Теперь, хотя это здорово, когда просто перебираешь параметр этого типа, мне непонятно, что делать, когда вам нужно передать его в функции PHP, которые принимают только array или просто Traversable. Например, если вы хотите выполнить array_diff, и ваш iterable равен Traversable, вы получите array. И наоборот, если вы вызовете функцию, которая принимает итератор, вы получите ошибку, если iterable является array.

Есть ли что-то вроде iterable_to_array (НЕ: iterator_to_array) и iterable_to_traversable?

Я ищу решение, которое позволяет избежать условностей в моих функциях, просто чтобы устранить эту разницу, и это не зависит от того, определяю ли я свои собственные глобальные функции.

Использование PHP 7.1

Author: Jeroen De Dauw, 2017-06-16

5 answers

Не уверен, что это то, что вы ищете, но это самый короткий способ сделать это.

$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(), но поскольку это языковая конструкция, она немного особенная. Он также не сохраняет ключи в ассоциативных массивах.

 6
Author: Edwin Rodríguez, 2017-06-16 12:03:24

Есть ли что-то вроде 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;
}
 1
Author: Sara, 2017-06-16 15:52:36

Термины легко смешивать

  • Проходимый
    • Итератор (я рассматриваю это как конкретный тип, например, самодельный класс A)
    • Объединение итераторов
  • итерируемый (это псевдотип , массив или проходимые принимаются)
  • массив (это конкретный тип, и он не подлежит обмену с итератором в контексте того, что требуется тип итератора)
  • ArrayIterator (может использоваться для преобразования массива в итератор)

Итак, вот почему, если функция A(итерируемая $a){}, то она принимает параметр либо массива, либо экземпляра , проходимого (Итератор, IteratorAggregate оба принимаются, потому что очевидно, что эти два класса реализуют Проходимый. В моем тесте передача ArrayIterator также работает).

В случае, если для параметра указан тип итератора, передача в массив приведет к ошибке типа.

 1
Author: Nero, 2018-10-03 08:31:24

Вы можете использовать iterator_to_array преобразование вашей переменной в Traversable первый:

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

Метод преобразования взят из комментария под этим вопросом.

Вот рабочая демонстрация.

 0
Author: sevavietl, 2017-06-18 07:12:24

Для случая "с возможностью итерирования в массив" кажется, что вы не можете выполнить ни одного вызова функции, и вам нужно будет либо использовать условие в своем коде, либо определить свою собственную функцию, например, так:

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

Для случая "от итерации к итератору" все намного сложнее. Массивы могут быть легко переведены в Traversable с помощью ArrayIterator. Iterator экземпляры могут быть просто возвращены такими, какие они есть. Это оставляет экземпляры Traversable, которые не являются экземплярами Iterator. На первый взгляд кажется, что вы можете использовать IteratorIterator, для чего требуется Traversable. Однако этот класс прослушивается и не работает должным образом при предоставлении ему IteratorAggregate, который возвращает Generator.

Решение этой проблемы слишком длинное, чтобы публиковать его здесь, хотя я создал мини-библиотеку, содержащую обе функции преобразования:

  • функция iterable_to_iterator (итерируемый $итерируемый): Итератор
  • функция iterable_to_array(повторяемый $повторяемый): массив

См. https://github.com/wmde/iterable-functions

 0
Author: Jeroen De Dauw, 2018-10-04 10:17:46