PHP iterierbar zu Array oder durchquerbar

Lesezeit: 4 Minuten

Ich bin sehr froh, dass PHP 7.1 eingeführt wurde der iterierbare Pseudotyp.

Während dies großartig ist, wenn man einfach einen Parameter dieses Typs durchläuft, ist mir unklar, was zu tun ist, wenn man ihn an PHP-Funktionen übergeben muss, die nur einen Parameter akzeptieren array oder einfach nur ein Traversable. Wenn Sie beispielsweise einen array_diff ausführen möchten, und Ihr iterable ist ein TraversableSie erhalten eine array. Wenn Sie umgekehrt eine Funktion aufrufen, die einen Iterator benötigt, erhalten Sie eine Fehlermeldung, wenn der iterable ist ein array.

Gibt es so etwas wie iterable_to_array (NICHT: iterator_to_array) Und iterable_to_traversable?

Ich suche nach einer Lösung, die Bedingungen in meinen Funktionen vermeidet, nur um diesen Unterschied auszugleichen, und die nicht davon abhängt, dass ich meine eigenen globalen Funktionen definiere.

Verwendung von PHP 7.1

Ich bin mir nicht sicher, ob das das ist, wonach Sie suchen, aber das ist der kürzeste Weg, es zu tun.

$array = [];
array_push ($array, ...$iterable);

Ich bin mir nicht ganz sicher, warum es funktioniert. Ich fand Ihre Frage gerade interessant und fange an, mit PHP herumzuspielen

Vollständiges Beispiel:

<?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());

Es wäre schön, wenn es mit der Funktion funktionieren würde array(), aber da es sich um ein Sprachkonstrukt handelt, ist es etwas Besonderes. Außerdem werden Schlüssel in Assoc-Arrays nicht beibehalten.

  • Dies funktioniert, weil array_push eine variable Anzahl von Argumenten akzeptiert und Sie das Iterable mit … in eine Liste von Argumenten entpacken. Für mich keine akzeptable Lösung, da eine zusätzliche Variable in den Gültigkeitsbereich eingefügt und dann geändert werden muss.

    – Jeroen De Dauw

    16. Juni 2017 um 14:13

  • @JeroenDeDauw Ich weiß, dass … es entfaltet, aber in array() funktioniert es nicht auf die gleiche Weise, also ist etwas Seltsames daran. Ich stimme zu, dass dies keine akzeptable Lösung ist. Tatsächlich denke ich, dass dies in 7.1 nicht möglich ist, aber angesichts der Einschränkungen (keine Definition von Funktionen und Verwendung von Bedingungen) die beste Lösung ist, die ich gefunden habe.

    – Edwin Rodríguez

    16. Juni 2017 um 17:47 Uhr


  • funktioniert für den Generator nicht, wenn der Generator nichts zurückgibt. dann erscheint ein Fehler – es wurden keine Argumente übergeben array_pushseit ... wird sich zu nichts auflösen.

    – Oleg Abrazhaev

    21. Okt. 2019 um 8:08

  • Seit PHP 7.3 wird bei Verwendung des obigen Codes kein Fehler mehr für leere Iterables ausgegeben. array_push kann nur mit dem ersten Argument aufgerufen werden.

    – dakujem

    8. März 2021 um 9:55 Uhr

Benutzer-Avatar von Michael Petri
Michael Petri

Für PHP >= 7.4 funktioniert das sofort ziemlich gut:

$array = [...$iterable];

Sehen https://3v4l.org/L3JNH

Bearbeiten: Funktioniert nur, solange die Iterable keine Zeichenfolgenschlüssel enthält

  • Funktioniert jetzt mit String-Schlüsseln in PHP 8.1: 3v4l.org/UkdLD

    – BenMorel

    8. November 2021 um 11:54

Kann so gemacht werden:

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

Gibt es so etwas wie iterable_to_array und iterable_to_traversable?

Fügen Sie diese einfach irgendwo zu Ihrem Projekt hinzu. Sie beanspruchen nicht viel Platz und bieten Ihnen genau die APIs, nach denen Sie gefragt haben.

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

Neros Benutzeravatar
Nero

Begriffe lassen sich leicht vermischen

  • Überfahrbar
    • Iterator (ich sehe das als einen konkreten Typ, wie die benutzerdefinierte Klasse A)
    • IteratorAggregate
  • iterierbar (das ist ein Pseudotyp, Array oder überfahrbar sind akzeptiert)
  • Array (Dies ist ein konkreter Typ und kann nicht mit Iterator ausgetauscht werden, da ein Iterator-Typ erforderlich ist.)
  • arrayIterator (kann zum Konvertieren eines Arrays in einen Iterator verwendet werden)

Deshalb akzeptiert die Funktion A(iterable $a){} Parameter entweder eines Arrays oder einer Instanz von überfahrbar (Iterator und IteratorAggregate werden beide akzeptiert, da es offensichtlich ist, dass diese beiden Klassen implementiert werden Überfahrbar. In meinem Test funktioniert auch die Übergabe von ArrayIterator.

Falls der Iteratortyp als Parameter angegeben ist, führt die Übergabe eines Arrays zu TypeError.

Benutzeravatar von TimWolla
TimWolla

Beginnend mit PHP 8.2 iterator_to_array() Und iterator_count() Funktionen werden akzeptiert iterable anstatt Traversable. So werden sie anfangen zu akzeptieren arrays und tun, was Sie von ihnen erwarten würden, wenn sie auf ein Array stoßen.

Im Einzelnen gelten folgende Gleichheiten:

iterator_to_array($array, true) == $array
iterator_to_array($array, false) == array_values($array)

Und

iterator_count($array) == count($array)

Weitere Details finden Sie im entsprechenden RFC: PHP RFC: Sorgen Sie dafür, dass die iterator_*()-Familie alle Iterables akzeptiert.

Benutzeravatar von sevavietl
sevavietl

Sie können verwenden iterator_to_array Konvertieren Sie Ihre Variable in Traversable Erste:

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

Die Konvertierungsmethode stammt aus dem Kommentar unter dieser Frage.

Hier ist funktionierende Demo.

  • Sie können Ihre iterierbare Eigenschaft einfach in ein Array umwandeln $array = (array) $iterable;

    – Fabien Salles

    31. Okt. 2019 um 16:17 Uhr

1452960cookie-checkPHP iterierbar zu Array oder durchquerbar

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy