web-dev-qa-db-ja.com

PHP配列またはトラバース可能に反復可能

PHP 7.1が導入されたこと 反復可能な疑似タイプ

これは、このタイプのパラメーターをループするだけの場合は優れていますが、それをPHP arrayまたはTraversableのみを受け入れる関数に渡す必要がある場合の対処方法がわかりません。たとえば、array_diffを実行する場合、iterableTraversableの場合、arrayを取得します。逆に、イテレーターを使用する関数を呼び出すと、iterablearrayの場合にエラーが発生します。

iterable_to_array(NOT:iterator_to_array)やiterable_to_traversableのようなものはありますか?

この違いを処理するためだけに関数の条件を回避するソリューションを探しています。これは、自分のグローバル関数を定義することに依存しません。

PHP 7.1を使用する

11
Jeroen De Dauw

「配列に反復可能」の場合、実行できる単一の関数呼び出しはなく、コードで条件を使用するか、次のような独自の関数を定義する必要があるようです。

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を指定すると正しく機能しません。

両方の変換関数を含むミニライブラリを作成しましたが、この問題の解決策は長すぎてここに投稿できません。

  • function iterable_to_iterator(iterable $ iterable):イテレータ
  • function iterable_to_array(iterable $ iterable):配列

https://github.com/wmde/iterable-functions を参照してください

1
Jeroen De Dauw

これがあなたが探しているものであるかどうかはわかりませんが、これはそれを行うための最短の方法です。

_$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()で動作するのはいいことですが、それは言語構造であるため、少し特別です。また、assoc配列のキーも保持しません。

7

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;
}
3
Sara

用語は簡単に組み合わせることができます

  • トラバース可能
    • イテレータ(これは、use-definedクラスAのような具体的なタイプだと思います)
    • IteratorAggregate
  • iterable(これはpseudo-type、arrayまたはtraversableが受け入れられます)
  • 配列(これは具象型であり、イテレータ型が必要であるという文脈ではイテレータと交換できません)
  • arrayIterator(配列をイテレータに変換するために使用できます)

したがって、関数A(iterable $ a){}の場合、配列またはインスタンスのいずれかのパラメーターを受け入れますtraversable(Iterator、IteratorAggregateは、これら2つのクラスが実装していることが明らかであるため両方とも受け入れられますTraversable。私のテストでは、ArrayIteratorに合格することもできます)。

パラメータにイテレータタイプが指定されている場合、配列を渡すとTypeErrorが発生します。

2
Nero

iterator_to_array 変数を Traversable に変換する最初に:

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

変換方法は この質問 の下のコメントから取られます。

これが 作業デモ です。

1
sevavietl

このように行うことができます:

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