PHP 7: Typsichere Arrays von Objekten

Mit PHP 7 kann man sich dazu entscheiden, typsichereren Code zu schreiben als zuvor, dank skalaren Type Hints und Rückgabetypen.

function repeat(string $text, int $times) : string;

Aber was ist mit Arrays? Es gibt immer noch nur den generischen “array” Type Hint, man kann nicht spezifizieren was das Array enthält. Für die IDE kann man PhpDoc Kommentare hinzufügen:

/**
 * @return User[]
 */
function allUsers() : array;

Jetzt können IDEs wie PhpStorm mit Code-Vervollständigung für Elemente des zurückgegebenen Arrays helfen. Aber wir können nicht von Prüfungen zur Laufzeit profitieren, wie mit echten Type Hints.

Für Argumente gibt es einen partiellen Workaround mit variadischen Argumenten. Nehmen wir die folgende Funktion:

/**
 * @param User[] $users
 */
function deleteUsers(array $users);

Mit variadischen Argumenten können wir sie umschreiben zu:

function deleteUsers(User ...$users);

Die Benutzung ändert sich auch, zu deleteUsers(...$users); Bei diesem Aufruf wird das Argument $users in einzelne Variablen “unpacked”, und in der Methode selbst wieder in ein Array $users “packed”. Jedes Element wird dabei auf den Typ User validiert. $users kann auch ein Iterator sein, er wird dann beim Aufruf in ein Array konvertiert.

Leider gibt es keinen entsprechenden Workaround für Rückgabetypen, und es funktioniert nur mit dem letzten Argument.

Siehe auch: Type hinting in PHP 7 – array of objects

Ich nutze diese Technik oft in PHP 7 Code, aber es gibt noch eine andere, die die genannten Schwächen nicht hat:
Continue reading “PHP 7: Typsichere Arrays von Objekten”

PHP Array Path

Hier mal ein kleines Snippet 1 um auf ein bestimmtes Element in verschachtelten Arrays zuzugreifen. Nützlich, wenn ein String der Form "key1.key2.key3" vorliegt, und damit auf $array['key1']['key2']['key3'] zugegriffen werden soll.

Funktionen

<?php
/**
  * @param string $spec Spezifikation in der Form 'item_1.item_2.[...].item_n=wert'
  * @param array $array Ziel-Array
  */
function insert_into_array($spec, &$array)
{
    list($path,$value) = explode('=', $spec, 2);
    $current =& $array;
    // setze Referenz $current Schritt für Schritt auf $array['item_1']['item_2'][...]['item_n']
    foreach(explode('.', $path) as $key) {
        $current =& $current[$key];
    }
    // belege dieses Array-Element mit $value
    $current = $value;
}  
/**
 * @param string $path Pfad in der Form 'item_1.item_2.[...].item_n'
 * @param array $array Ursprungs-Array
 */
function &get_from_array($path, &$array)
{
    $current =& $array;
    foreach(explode('.', $path) as $key) {
        $current =& $current[$key];
    }
    return $current;
}

Beispiel: Nutzung

$array = array();
insert_into_array('item.test.6.12134.12.12.343=4546', $array);
insert_into_array('item.test.23=foo', $array);
var_dump(get_from_array('item.test', $array));

Beispiel: Ausgabe

array(2) {
  [6] =>
  array(1) {
    [12134] =>
    array(1) {
      [12] =>
      array(1) {
        ...
      }
    }
  }
  [23] =>
  string(3) "foo"
}

Notes:

  1. Ausgehend von dieser Forumsdiskussion