PHP: Was bedeutet dieses Zeichen?

Nach einem Sonderzeichen zu suchen ist mühsam. Genau deshalb stolpert man in fremdem PHP-Code immer wieder über Operatoren, die man nicht einordnen kann. Dieser Artikel geht die durch, bei denen das am häufigsten passiert.

Alle Ausgaben in diesem Artikel stammen aus einem Skript das ich gegen PHP 8.5.9 laufen lassen habe.

== und === (Type Juggling)

== vergleicht nach einer automatischen Typumwandlung, === vergleicht zusätzlich den Datentyp:

'1' == '01'     => true
'10' == '1e1'   => true
100 == '1e2'    => true
'1' === '01'    => false

Zwei numerische Strings werden also als Zahlen verglichen. Achtung, ein Klassiker hat sich mit PHP 8 geändert:

0 == 'a'        => false

Vor PHP 8 war das true. Der String wurde damals nach int umgewandelt, was 0 ergab. Seit PHP 8 wird stattdessen die Zahl in einen String umgewandelt. Steht in einem älteren Tutorial etwas anderes, ist das der Grund.

Im Zweifelsfall nimmst du ===.

?: und ?? sind nicht dasselbe

Das ist der Punkt, bei dem die meisten hereinfallen, und er steht sogar auf Stack Overflow falsch. Die Kurzschreibweise des Ternary (?:, oft “Elvis Operator” genannt) prüft auf truthy. Der Null Coalescing Operator (??, seit PHP 7) prüft auf null:

<?php
  $zero = 0;

  echo $zero ?: 'Ersatzwert';   // 'Ersatzwert'  -- 0 ist falsy
  echo $zero ?? 'Ersatzwert';   // 0             -- 0 ist nicht null
?>

Bei 0, '' oder [] verhalten sich die beiden also unterschiedlich. Dazu kommt: ?? unterdrückt zusätzlich die Warnung bei nicht existierenden Array-Schlüsseln, ?: nicht.

<?php
  $arr = [];
  echo $arr['fehlt'] ?? 'Standard';   // 'Standard', keine Warnung
?>

?? lässt sich auch verketten. Der erste Wert der existiert und nicht null ist, gewinnt:

<?php
  $name = $_GET['user'] ?? $_POST['user'] ?? 'niemand';
?>

Seit PHP 7.4 gibt es dazu die Zuweisung ??=. Sie setzt einen Wert nur dann, wenn er noch nicht gesetzt ist:

<?php
  $config = ['host' => 'localhost'];
  $config['port'] ??= 3306;              // wird gesetzt
  $config['host'] ??= 'wird ignoriert';  // bleibt 'localhost'
?>

?-> Nullsafe Operator

Seit PHP 8.0. Der Operator bricht die Kette ab und liefert null, statt einen Fehler zu werfen:

$mitName?->name?->first     => 'Ada'
$ohneName?->name?->first    => NULL

Damit ersparst du dir verschachtelte Prüfungen. Ein Detail: Auf Array-Schlüssel wirkt der Operator nicht, dort bekommst du weiterhin eine Warnung.

<=> Spaceship Operator

Seit PHP 7.0. Er vergleicht in eine Richtung und gibt 0, einen negativen oder einen positiven Wert zurück:

1 <=> 2             => -1
2 <=> 1             => 1
"a" <=> "a"         => 0
[1,2,3] <=> [1,2,4] => -1

Der Hauptanwendungsfall sind Vergleichsfunktionen, etwa bei usort():

<?php
  $zahlen = [4, 2, 1, 3];
  usort($zahlen, fn($a, $b) => $a <=> $b);   // [1, 2, 3, 4]
?>

Ein häufiger Fehler ist es, stattdessen $a - $b zu schreiben. Das geht schief, sobald Fließkommazahlen im Spiel sind, weil usort() den Rückgabewert nach int wandelt. Der Unterschied zwischen 4 und 4.6 wird damit zu 0, also “gleich”.

… die drei Punkte

Die drei Punkte machen je nach Position drei verschiedene Dinge.

Variadische Parameter (seit PHP 5.6), also beliebig viele Argumente:

<?php
  function summe(int ...$zahlen): int {
    return array_sum($zahlen);
  }
  echo summe(1, 2, 3);   // 6
?>

Argument Unpacking, also ein Array auseinandernehmen:

summe(...[10, 20, 30])   => 60

Mit assoziativen Arrays funktioniert das wie benannte Argumente, die Reihenfolge spielt dann keine Rolle mehr:

fullName(...['last' => 'Lovelace', 'first' => 'Ada'])   => 'Ada Lovelace'

First Class Callable Syntax (seit PHP 8.1). Damit machst du aus einer Funktion einen Wert:

<?php
  $upper = strtoupper(...);
  echo $upper('abc');   // ABC
?>

=> und -> und ::

Diese drei werden gerne verwechselt.

=> trennt in einem Array Schlüssel und Wert:

<?php
  $arr = ['year' => 2026];
  echo $arr['year'];   // 2026
?>

-> greift auf etwas an einem Objekt zu, :: auf etwas an der Klasse selbst (Konstanten, statische Methoden und Eigenschaften):

<?php
  echo (new Counter)->value;      // Instanz
  echo Counter::START;            // Konstante
  echo Counter::make()->value;    // statische Methode
?>

. und + bei Arrays

Der Punkt verkettet Strings. Bei Arrays ist + aber nicht dasselbe wie array_merge():

[1,2] + [9,9,9]              => [1, 2, 9]
array_merge([1,2], [9,9,9])  => [1, 2, 9, 9, 9]

+ ist die Vereinigungsmenge: Ein Schlüssel der links schon existiert, wird rechts nicht übernommen. array_merge() nummeriert numerische Schlüssel neu und verliert daher nichts.

@ Fehlerkontrolloperator

Das @ unterdrückt Fehlermeldungen eines Ausdrucks:

@file_get_contents('/gibt/es/nicht')   => false

Die Warnung ist weg, aber der Aufruf ist trotzdem fehlgeschlagen. Genau das ist das Problem: Man sieht nicht mehr, dass etwas schief gegangen ist, muss den Rückgabewert aber weiterhin prüfen. Nutze @ also möglichst gar nicht.

«< Heredoc und Nowdoc

Beide erlauben mehrzeilige Strings. Der Unterschied liegt in den Anführungszeichen um den Bezeichner:

Heredoc  (<<<TXT)     => 'hello world'
Nowdoc   (<<<'TXT')   => 'hello $who'

Heredoc verhält sich wie ein String in doppelten Anführungszeichen und setzt Variablen ein. Nowdoc verhält sich wie einfache Anführungszeichen und lässt alles stehen.

|> Pipe Operator

Neu in PHP 8.5. Er reicht das Ergebnis nach rechts weiter, sodass man verschachtelte Aufrufe von links nach rechts lesen kann:

<?php
  $titel = '  PHP 8.5 Released  ';

  $slug = $titel
    |> trim(...)
    |> (fn($s) => str_replace(' ', '-', $s))
    |> (fn($s) => str_replace('.', '', $s))
    |> strtolower(...);

  // 'php-85-released'
?>

Vor PHP 8.5 musste man dasselbe von innen nach außen schreiben:

<?php
  $slug = strtolower(str_replace('.', '', str_replace(' ', '-', trim($titel))));
?>

** und %

** ist die Potenz (seit PHP 5.6), % der Rest einer Division:

2 ** 10   => 1024
7 % 3     => 1
-7 % 3    => -1

Beim Modulo richtet sich das Vorzeichen des Ergebnisses nach dem linken Operanden. Wer den Rest immer positiv braucht, kommt daran nicht vorbei.

Und der Rest?

Die vollständige Liste aller Zeichen findest du in der Liste der Parser-Token im PHP Handbuch. Nicht behandelt haben wir hier bewusst die Bit-Operatoren (&, |, ^, ~, <<, >>) und die variablen Variablen ($$) — dazu später vielleicht mehr.

Hinweis zu Netcup (Werbung)

Der deutsche Hoster Netcup bietet unter anderem günstige und zugleich leistungsstarke Webhosting Pakete, KVM-basierte Root Server und dezidierte Server an. Mit unseren Gutscheincodes kannst du noch mehr Geld sparen (6€ bei deiner ersten Bestellung, 30% Rabatt auf alle KVM-basierten Root Server, ...).