PHP Array, Improved

Python kanns, Ruby kanns, Ja sogar Java kanns. Nur PHP nicht. Nun, das stimmt nicht so ganz, PHP kann es über Umwege doch. Wovon die Rede ist?

Objekte als Hashtabellen-Schlüssel verwenden

Wie der eine oder andere Anwender von PHP weiß, können assoziative Arrays nur Integer und Zeichenketten als Schlüssel verwenden. Das ist manchmal sehr schade und man muss auf andere Werkzeuge ausweichen, indem man sich z.B. mit array_unique() und ArrayAccess sowie Iterator selbst etwas zurecht schustert.
Es gibt allerdings auch eine relativ elegante Lösung für dieses Problem: Die SplObjectStorage Klasse
Mit dieser Klasse aus der PHP SPL ist es möglich eine Datenstruktur zu schaffen, die sich wie ein assoziatives Array verhält, zugleich jedoch auch Objekte als Schlüssel erlaubt. Ein kleines Beispiel:

 1, 'prop2' => 2);
$obj2 = (object) array('prop1' => 11, 'prop2' => 22);
$obj3 = (object) array('prop1' => 11, 'prop2' => 22);
$objStorage = new SplObjectStorage();
$objStorage[$obj1] = 3;
$objStorage[$obj2] = 33;
$objStorage->contains($obj1); // TRUE
$objStorage->contains($obj2); // TRUE
$objStorage->contains($obj3); // FALSE
echo $objStorage[$obj1]; // 3
echo $objStorage[$obj2]; // 33
echo $objStorage[$obj3]; // UnexpectedValueException

Zu beachten ist, dass man zwar über ein Exemplar der Klasse SplObjectStorage iterieren kann, mit der $x as $y => $z Syntax jedoch unerwartetes Verhalten auftritt. In diesem Beispiel ist nämlich nicht $y das Objekt, sondern $z. $y entspricht der internen Position des Iterators. Nutzt man hingegen die $x as $y Syntax, ist $y das Objekt und man muss über $x[$y] auf dessen Wert zugreifen.
Ich hoffe ich konnte einen hilfreichen, wenn auch kurzen Einblick in die Klasse SplObjectStorage bieten. Dies war jedoch wirklich nur ein kleiner Ausschnitt, mehr kann über die Dokumentation erfahren werden.

Johannes Meyer
Johannes Meyer
Developer

Johannes ist seit 2011 bei uns und hilft bei der Entwicklung zukünftiger Knüller (Icinga2, Icinga Web 2, ...) aus dem Hause NETWAYS.

PHP SPL: Queue

Wer mit PHP eine performante Warteschlange realisieren will, dem sei es mit einer SplQueue geholfen, die ebenfalls ab  der PHP Version 5.3.0 vorhanden ist.
Die Funktionsweise an sich ist relativ einfach, die SplQueue arbeitet nach dem FIFO Prinzip und implementiert die SplDoublyLinkedList über die bereits Matthias einen Beitrag verfasst hatte.
Die wichtigsten Methoden sind:

  • enqueue() – Element ans Ende der Warteschlange hinzufügen.
  • dequeue() – Das Erste Element aus der Warteschlange herausnehmen.

Folgendes Beispiel soll die Nutzung verdeutlichen:

enqueue('research');
$queue->enqueue('planning');
$queue->enqueue('development');
$queue->dequeue();
$queue->dequeue();
echo $queue->top() . PHP_EOL; // development

Und da wir bei einer SplQueue über den ArrayAccess-Interface verfügen, können wir die Elemente auch nach dem folgenden Schema hinzufügen.

dequeue();
$queue->dequeue();
echo $queue->top() . PHP_EOL; // development

Ein praktischer Einsatz von SplQueue wäre mit Sicherheit es in PHP Daemons zu verwenden, wo auf Performance und geringen Speicherverbrauch Wert gelegt wird.
Wer mehr Beispiele haben will oder herausfinden will wo die SplQueue alles verwendet wird, kann sich durchs GitHub durchstöbern.

PHP Arrays filtern, Improved

Jeder der schonmal mit PHP in Berührung kam kennt vermutlich array_filter. Dieses kleine Schmuckstück ist manchmal ganz praktisch, kann jedoch nicht mit assoziativen Arrays umgehen. Die PHP SPL bietet jedoch seit Version 5.1 eine nette Alternative: Den FilterIterator
(mehr …)

Johannes Meyer
Johannes Meyer
Developer

Johannes ist seit 2011 bei uns und hilft bei der Entwicklung zukünftiger Knüller (Icinga2, Icinga Web 2, ...) aus dem Hause NETWAYS.

PHP SPL: Verkettete Listen

Eine nützliche Klasse die durch SPL ihren Einzug in PHP gefunden hat, ist die SplDoublyLinkedList, die Implementierung einer doppelt verketteten Liste.
Eine verkettete Liste ist eine dynamisch erweiterbare Datenstruktur, die beliebig viele Elemente speichern und enumerieren kann. In vielen Sprachen, in denen die Größe von Arrays bereits statisch beim Erstellen festgelegt wird, sind Listen deshalb ein wichtiger Grundbaustein um wachsende Datenstrukturen zu Implementieren. Da Arrays in PHP diese Einschränkungen nicht haben und damit generell bereits alle Möglichkeiten einer Liste bieten, gab es lange Zeit keine Implementierung in der PHP-Standardbibliothek.
Das verwenden einer SplDoubleLinkedList macht aber in vielen Bereich dennoch Sinn, da diese das Einfügen von Elementen an bestimmten Positionen einfacher und performanter macht. Wenn wir in einem normalen Array ein Element an einem bestimmten Index einfügen wollen ohne ein Element zu überschreiben, können wir array_splice verwenden.

$N = 10000;
$arr = array('foo', 'bar', 'baz');
for ($i = 0; $i < $N; $i++) {
    array_splice($arr, 1, 0, $item);
}

Wie wir feststellen ist diese Implementierung nicht sonderlich performant und das Einfügen von 10000 Elementen dauert bereits fast 10 Sekunden.

time php -f ./insert_at_array.php
real 0m10.116s
user 0m10.077s
sys 0m0.024s

Die SplDoublyLinkedList beherrscht seit Version 5.5 die Funktion SplDoublyLinkedList::add, die ein Element an eine bestimmte Position in die Liste einfügen kann.

$N = 10000;
$list = new SplDoublyLinkedList();
$list->push('foo');
$list->push('bar');
$list->push('baz');
for ($i = 0; $i < $N; $i++) {
    $list->add(1, $i);
}

Time verrät uns, dass diese Implementierung mit 47ms mehr als 200 mal schneller durchläuft als die mit regulären Arrays.

time php -f ./insert_at_list.php
real 0m0.047s
user 0m0.036s
sys 0m0.008s

Erklären lässt sich dieser Unterschied mit der internen Implementierung von Arrays in PHP. Diese sind in PHP eigentlich Hash-Tabellen, weshalb beim Aufruf von array_splice, alle nachfolgenden Elemente mit einem neuen Index versehen werden müssen. In einer verketteten Liste wird der Index eines Elements nicht gespeichert, sondern nur anhand der Position in der Kette aus Elementen definiert. Hier genügt es die Referenzen des Vorgängers und des Nachfolgers zu ändern um alle Nachfolger einen Index nach hinten zu verschieben.
 

PHP SPL: Heaps

Viele Daten im Nachhinein zu sortieren kostet Zeit. Seit PHP Version 5.3 gibt es in der SPL die Heap Klassen welche eine Sortierung on-the-fly erlauben. PHP stellt eine generische Heap Klasse bereit (hier im unteren Beispiel) um eigenen Datentypen zu vergleichen. Es gibt aber auch eigene Klassen für Min- und Max-Heaps.
Heap Strukturen eignen sich im Allgemeinen erst bei einer größeren Menge an Daten. So ist ein Max-Heap mit 1.000.000 Einträgen fast um ein drittel schneller als ein konventionelles Array welches anschließend eine absteigende Sortierung erfährt.

class TimestampMaxHeap extends SplHeap
{
    public function compare($array1, $array2)
    {
        if ($array1[0] === $array2[0]) {
            return 0;
        }
        return $array1[0] < $array2[0] ? -1 : 1;
    }
}
$heap = new TimestampMaxHeap();
$heap->insert(array(new DateTime('2014-01-04'), 4));
$heap->insert(array(new DateTime('2014-01-01'), 1));
$heap->insert(array(new DateTime('2014-01-06'), 6));
$heap->insert(array(new DateTime('2014-01-03'), 3));
$heap->insert(array(new DateTime('2014-01-05'), 5));
$heap->insert(array(new DateTime('2014-01-02'), 2));
foreach ($heap as $entry) {
    echo $entry[1] . ' ';
}
echo PHP_EOL;
Marius Hein
Marius Hein
Head of Development

Marius Hein ist schon seit 2003 bei NETWAYS. Er hat hier seine Ausbildung zum Fachinformatiker absolviert, dann als Application Developer gearbeitet und ist nun Leiter der Softwareentwicklung. Ausserdem ist er Mitglied im Icinga Team und verantwortet dort das Icinga Web.

Weekly Snap: Puppet Camp CfP, PHP SPL & OSMC

weekly snap23 – 27 June ended the month with tips for PHP developers, sys admins and business travellers, while shining the spotlight on our upcoming events.
At 155 days, Eva started her countdown to the Open Source Monitoring Conference with Luca Deri’s talk on “Monitoring Network Traffic Using Ntopng”, and Bernd followed with his OSMC reflections in suit.
Eva went on to open the Puppet Camp Call for Papers in full song and dance, as Christian reminded readers to join the Foreman / OpenNebula webinar.
Sebastian then explained how to replicate ZFS file systems with zrep, and Eric began a new blog series on PHP’s SPL with an example of ‘peek ahead during iteration’.
To end the week, Tobias shared his flight-booking tips for business travellers.

PHP SPL: Peek Ahead During Iteration

Eines der “Glanzstücke” von PHP und definitiv eine Blog-Serie wert, ist die seit Version 5.0.0 verfügbare SPL.
Was ist das?
SPL ist die Standard PHP Library, die laut dem PHP-Handbuch eine Sammlung von Interfacen und Klassen für die Lösung von Standardproblemen ist. Wer Klassen und Interfaces aus der SPL verwendet, die quasi eine API zu den intern eingebauten PHP Funktionen sind, kann mit Standardmitteln voll objektorientierten Code schreiben.
Nachfolgend das erste Beispiel dieser Serie.
Peek ahead during iteration

getInnerIterator()->valid() ?
        $cachingIterator->getInnerIterator()->current() : 'eoi') . PHP_EOL;
}
Eric Lippmann
Eric Lippmann
Lead Senior Developer

Eric kam während seines ersten Lehrjahres zu NETWAYS und hat seine Ausbildung bereits 2011 sehr erfolgreich abgeschlossen. Seit Beginn arbeitet er in der Softwareentwicklung und dort an den unterschiedlichen NETWAYS Open Source Lösungen, insbesondere inGraph und im Icinga Team an Icinga Web. Darüber hinaus zeichnet er sich für viele Kundenentwicklungen in der Finanz- und Automobilbranche verantwortlich.