PHP ist ja eine Sprache, die viele lieben und (zumindest gefühlt) noch mehr hassen. Auch wenn gerade die zweite Gruppe das nicht gerne hört, aber PHP ist aktuell die Sprache, die am häufigsten für Backendanwendungen im Web verwendet wird.

w3techs.com veröffentlicht regelmäßig Zahlen zur Nutzung von Webtechnologien im Zusammenhang mit der Häufigkeit. So ermittelt w3techs.com, dass derzeit 78,9% aller Websiten serverseitig auf PHP basieren. Eine andere Statistik ermittelt SimilarTech, die die absoluten Einsätze von PHP zählt und auf eine Zahl von 7.394.225 Websiten kommen. Im Vergleich dazu Python mit 123.879.

Fakt ist also, dass PHP noch da ist. Deswegen, aus Interesse an der Sprache und auch aus anderen sehr guten (beruflichen) Gründen befasse ich mich nun wieder verstärkt damit. Meine letzte Reise mit PHP schon eine ganze Weile her.

PHP 7 entwickelt sich. Und irgendwie auch nicht.

PHP hatte schon immer alte Zöpfe; das wissen wir alle. Mit der Version 7 konnten die Entwicklern der Sprache diese auf jeden Fall deutlich aufwerten und verbessern. Golem hat dazu einen schönen Artikel darüber rausgebracht, welche Features die Sprache ihr eigen nennen darf. Die offizielle Doku dazu findet sich auf der Homepage von PHP.

Die alte Seele hat die Sprache aber immer noch …

Scoping (oder auch nicht)

Ein Freund von mir schickte mir folgenden Code und fragte mich, welche Ausgabe ich bei den echo erwarte:

$arr = [1, 2, 3];
echo implode(", ", $arr), "\n";

foreach ($arr as &$val) {}
echo implode(", ", $arr), "\n";

foreach ($arr as $val) {}
echo implode(", ", $arr), "\n";

Nach einigem Überlegen kam ich auf folgendes Ergebnis:

// [ 1, 2, 3 ]
// [ 1, 2, 3 ]
// [ 1, 2, 3 ]

Aber, wen wundert es: Es ist nicht richtig.

foreach wird in PHP nicht gescoped. Das bedeutet, dass die Deklaration von $val in der ersten der beiden foreach Schleifen die Variable global anlegt.

Was passiert hier also genau?

In der ersten foreach Schleife wird $val die Referenz auf eine Stelle in $arr zugewiesen. In der letzten Iteration ist $val also eine Referenz auf $arr[2].

In der zweiten foreach Schleife passiert nun folgendes:

  1. Iteration: $val wird der Inhalt von $arr[0] zugewiesen. Da $val eine Referenz auf $arr[2] ist, ändert sich nicht der Wert von $val, sondern von $arr[2]. Somit sieht $arr nach der ersten Iteration so aus: [ 1, 2, 1].
  2. Iteration: Jetzt wird $val der Wert von $arr[1] zugewiesen, also 2. Da sich an den Referenzen nichts verändert hat, sieht $arr nun wie folgt aus: [ 1, 2, 2 ].
  3. Iteration: Das gleiche Spiel. $val wird nun der Wert von $arr[2] zugewiesen. Endergbenis: [ 1, 2, 2 ].

Generell ist die Funktionsweise von Referenzen jetzt kein Hexenwerk. Allerdings würde man das Verhalten hier so gar nicht erwarten, da man auf jeden Fall davon ausgehen würde, dass $val gescoped ist. Schließlich wurde es in einem foreach Kontext deklariert.

Um das Problem übrigens professionell zu lösen, empfiehlt sichh nach jeder foreach Schleife die explizite Dereferenzierung.

foreach ($arr as $val) {}
unset($val);

Irgendwie schade, dass man das nicht verbessert hat. Stattdessen gibt es jetzt einen

Spaceship Operator

Der Spaceship Operater ist ein Operator, welcher zwei Werte vergleicht. Im Grunde verhält sich der Operator wie eine Waage. Ist der linke Wert größer, ist das Ergebnis 1. Sind beide Werte gleich, so ist das Ergebnis der Operation 0. Ist der rechte Wert größer, -1.

// Integers
echo 1 <=> 1;  // 0
echo 1 <=> 2;  // -1
echo 2 <=> 1;  // 1

// Floats
echo 1.5 <=> 1.5 // 0
echo 1.5 <=> 2.5 // -1
echo 2.5 <=> 1.5 // 1

// Strings
echo "a" <=> "a" // 0
echo "a" <=> "b" // -1
echo "b" <=> "a" // 1

Praktisch? Useless? Ich bin mir selbst noch nicht so schlüssig. Auf jeden Fall ist auch diese Funktion mit Vorsicht zu genießen, vor allem beim vergleichen zweier Character, da hier lediglich der ASCII Tabellen Wert überprüft wird. Das heißt:

echo chr(42) <=> chr(43); // -1

Wie erwartet. Aber:

echo "a" <=> "A"; // 1

Auch wenn es logisch ist, dass "a" (ASCII Wert 97) größer ist, als "A" (ASCII Wert 65), ist es nicht sofort ersichtlich und wenig intuitiv.

Gespannt bleiben

Die Sprache hat noch einiges zu bieten. Da PHP mit die älteste Sprache im Webbereich ist, hat diese entsprechend auch die meisten Fehler und Probleme (gehabt). Es ist wirklich lehrreich zu erforschen, was genau moderne Sprachen wie besser machen. Und wie sich PHP selbst auch entwickelt und verbessert.

Ich denke, dass da wohl noch einige interessante learnings folgen werden …