PHP 7.1が導入されたこと 反復可能な疑似タイプ 。
これは、このタイプのパラメーターをループするだけの場合は優れていますが、それをPHP array
またはTraversable
のみを受け入れる関数に渡す必要がある場合の対処方法がわかりません。たとえば、array_diffを実行する場合、iterable
がTraversable
の場合、array
を取得します。逆に、イテレーターを使用する関数を呼び出すと、iterable
がarray
の場合にエラーが発生します。
iterable_to_array
(NOT:iterator_to_array
)やiterable_to_traversable
のようなものはありますか?
この違いを処理するためだけに関数の条件を回避するソリューションを探しています。これは、自分のグローバル関数を定義することに依存しません。
PHP 7.1を使用する
「配列に反復可能」の場合、実行できる単一の関数呼び出しはなく、コードで条件を使用するか、次のような独自の関数を定義する必要があるようです。
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
を指定すると正しく機能しません。
両方の変換関数を含むミニライブラリを作成しましたが、この問題の解決策は長すぎてここに投稿できません。
これがあなたが探しているものであるかどうかはわかりませんが、これはそれを行うための最短の方法です。
_$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配列のキーも保持しません。
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;
}
用語は簡単に組み合わせることができます
したがって、関数A(iterable $ a){}の場合、配列またはインスタンスのいずれかのパラメーターを受け入れますtraversable(Iterator、IteratorAggregateは、これら2つのクラスが実装していることが明らかであるため両方とも受け入れられますTraversable。私のテストでは、ArrayIteratorに合格することもできます)。
パラメータにイテレータタイプが指定されている場合、配列を渡すとTypeErrorが発生します。
iterator_to_array
変数を Traversable
に変換する最初に:
$array = iterator_to_array((function() use ($iterable) {yield from $iterable;})());
変換方法は この質問 の下のコメントから取られます。
これが 作業デモ です。
このように行うことができます:
$array = $iterable instanceof \Traversable ? iterator_to_array($iterable) : (array)$iterable;