8 Operatoren und Ausdrücke

Operatoren sind Symbole, die PHP anweisen, bestimmte Operationen mit Werten durchzuführen. Diese Werte, auch Operanden genannt, können Variablen, Konstanten oder Literale sein. Zusammen mit diesen Operanden bilden Operatoren Ausdrücke, die zu einem neuen Wert ausgewertet werden. In diesem Abschnitt werden wir die verschiedenen Arten von Operatoren in PHP und ihre Anwendung behandeln.

8.1 Arithmetische Operatoren

Diese Operatoren führen grundlegende mathematische Operationen durch:

<?php
$a = 10;
$b = 3;

echo $a + $b;    // 13 (Addition)
echo $a - $b;    // 7 (Subtraktion)
echo $a * $b;    // 30 (Multiplikation)
echo $a / $b;    // 3.3333... (Division)
echo $a % $b;    // 1 (Modulo - Rest der Division)
echo $a ** $b;   // 1000 (Potenzierung, seit PHP 5.6)

// Negation
echo -$a;        // -10 (Vorzeichenumkehr)
?>

8.1.1 Integer Division und Modulo

Die Division zweier Ganzzahlen führt in PHP im Gegensatz zu einigen anderen Sprachen zu einem Float-Ergebnis, wenn die Division nicht aufgeht. Der Modulo-Operator (%) ist nützlich, um zu prüfen, ob eine Zahl durch eine andere teilbar ist:

<?php
// Prüfen, ob eine Zahl gerade ist
$istGerade = ($zahl % 2 == 0);

// Für negative Zahlen folgt der Modulo-Operator in PHP dem Vorzeichen des Dividenden
echo -10 % 3;    // -1 (nicht 2)
echo 10 % -3;    // 1
?>

Seit PHP 7.0 gibt es die Integer-Division mit dem Operator intdiv():

<?php
echo intdiv(10, 3);    // 3 (Integer-Division)
?>

8.2 Zuweisungsoperatoren

Der Basis-Zuweisungsoperator ist =, der den Wert des rechten Operanden dem linken Operanden zuweist:

<?php
$a = 10;    // Weist $a den Wert 10 zu
?>

Es gibt auch kombinierte Zuweisungsoperatoren, die einen arithmetischen Operator mit einer Zuweisung verbinden:

<?php
$a = 10;

$a += 5;      // Äquivalent zu: $a = $a + 5;  (Ergebnis: 15)
$a -= 3;      // Äquivalent zu: $a = $a - 3;  (Ergebnis: 12)
$a *= 2;      // Äquivalent zu: $a = $a * 2;  (Ergebnis: 24)
$a /= 4;      // Äquivalent zu: $a = $a / 4;  (Ergebnis: 6)
$a %= 4;      // Äquivalent zu: $a = $a % 4;  (Ergebnis: 2)
$a **= 3;     // Äquivalent zu: $a = $a ** 3; (Ergebnis: 8)

// Für Strings:
$str = "Hallo";
$str .= " Welt";   // Äquivalent zu: $str = $str . " Welt"; (Ergebnis: "Hallo Welt")
?>

8.2.1 Referenzzuweisung

Der Referenzzuweisungsoperator =& weist keine Werte zu, sondern erstellt eine Referenz:

<?php
$a = 10;
$b =& $a;    // $b ist nun eine Referenz auf $a
$b = 20;     // Ändert auch $a auf 20
echo $a;     // 20
?>

8.3 Vergleichsoperatoren

Vergleichsoperatoren prüfen Beziehungen zwischen zwei Werten und geben einen booleschen Wert (true oder false) zurück:

<?php
$a = 5;
$b = '5';
$c = 10;

// Gleichheitsvergleiche
var_dump($a == $b);   // bool(true) - Gleich (Wert wird verglichen, Typ wird konvertiert)
var_dump($a === $b);  // bool(false) - Identisch (Wert UND Typ müssen gleich sein)
var_dump($a != $b);   // bool(false) - Ungleich (Wert wird verglichen, Typ wird konvertiert)
var_dump($a <> $b);   // bool(false) - Alternative Syntax für !=
var_dump($a !== $b);  // bool(true) - Nicht identisch (entweder Wert ODER Typ sind ungleich)

// Größenvergleiche
var_dump($a < $c);    // bool(true) - Kleiner als
var_dump($a > $c);    // bool(false) - Größer als
var_dump($a <= $c);   // bool(true) - Kleiner oder gleich
var_dump($a >= $c);   // bool(false) - Größer oder gleich

// Raumschiff-Operator (seit PHP 7.0)
echo $a <=> $c;       // -1 (wenn $a < $c)
echo $c <=> $a;       // 1 (wenn $c > $a)
echo $a <=> $a;       // 0 (wenn $a == $a)
?>

8.3.1 Besonderheiten bei Vergleichen in PHP

PHP führt bei Vergleichen mit == eine Typumwandlung durch, was zu unerwarteten Ergebnissen führen kann:

<?php
var_dump(0 == "0");       // bool(true)
var_dump(0 == "");        // bool(true)
var_dump(0 == false);     // bool(true)
var_dump("0" == false);   // bool(true)

// Für strikte Vergleiche immer === verwenden
var_dump(0 === "0");      // bool(false)
var_dump(0 === false);    // bool(false)
?>

8.4 Logische Operatoren

Logische Operatoren kombinieren boolesche Ausdrücke:

<?php
$a = true;
$b = false;

// Logisches UND
var_dump($a && $b);   // bool(false)
var_dump($a and $b);  // bool(false) - Alternative Syntax, niedrigere Präzedenz

// Logisches ODER
var_dump($a || $b);   // bool(true)
var_dump($a or $b);   // bool(true) - Alternative Syntax, niedrigere Präzedenz

// Logisches XOR (Exklusives ODER)
var_dump($a xor $b);  // bool(true) - Wahr, wenn entweder $a oder $b wahr ist, aber nicht beide

// Logisches NICHT
var_dump(!$a);        // bool(false)
?>

8.4.1 Kurzschlussauswertung (Short-circuit Evaluation)

Bei logischen Operatoren wie && und || wertet PHP nur so viele Ausdrücke aus wie nötig:

<?php
// Bei && wird der zweite Ausdruck nur ausgewertet, wenn der erste wahr ist
$a = false && funktionMitNebenwirkung();  // funktionMitNebenwirkung() wird nicht aufgerufen

// Bei || wird der zweite Ausdruck nur ausgewertet, wenn der erste falsch ist
$b = true || funktionMitNebenwirkung();   // funktionMitNebenwirkung() wird nicht aufgerufen
?>

8.4.2 Unterschied zwischen && und and, || und or

Die Operatoren && und || haben eine höhere Präzedenz als and und or, was zu Unterschieden bei komplexen Ausdrücken führen kann:

<?php
// Diese beiden Ausdrücke werden unterschiedlich ausgewertet
$a = false || true;    // $a ist true
$b = false or true;    // $b ist false, weil die Zuweisung eine höhere Präzedenz hat

$c = true && false;    // $c ist false
$d = true and false;   // $d ist true, weil die Zuweisung eine höhere Präzedenz hat
?>

8.5 Bitweise Operatoren

Bitweise Operatoren manipulieren die Bits der Operanden:

<?php
$a = 5;    // 101 in Binär
$b = 3;    // 011 in Binär

// Bitweises UND
echo $a & $b;    // 1 (001 in Binär)

// Bitweises ODER
echo $a | $b;    // 7 (111 in Binär)

// Bitweises XOR
echo $a ^ $b;    // 6 (110 in Binär)

// Bitweise Negation
echo ~$a;        // -6 (in Zweierkomplementdarstellung)

// Bitweise Verschiebung nach links
echo $a << 1;    // 10 (1010 in Binär)

// Bitweise Verschiebung nach rechts
echo $a >> 1;    // 2 (10 in Binär)
?>

Bitweise Operatoren sind nützlich für: - Setzten oder Prüfen einzelner Bits in Flags oder Optionen - Effiziente Multiplikation/Division durch Potenzen von 2 - Niedrige-Ebene-Operationen, z.B. für Bildmanipulation

8.6 String-Operatoren

PHP hat zwei Operatoren, die speziell für Strings sind:

<?php
// Konkatenation (Verkettung)
$a = "Hallo";
$b = "Welt";
echo $a . $b;         // "HelloWelt"
echo $a . " " . $b;   // "Hello Welt"

// Konkatenation mit Zuweisung
$a .= " " . $b;       // Äquivalent zu: $a = $a . " " . $b;
echo $a;              // "Hallo Welt"
?>

8.7 Array-Operatoren

PHP bietet spezielle Operatoren für Arrays:

<?php
$a = ["name" => "Max", "alter" => 30];
$b = ["stadt" => "Berlin", "name" => "Moritz"];

// Union-Operator
$c = $a + $b;  // Bei gleichen Schlüsseln behält der linke (erste) Operand den Wert
/*
$c enthält: [
    "name" => "Max",       // Aus $a, nicht überschrieben
    "alter" => 30,         // Aus $a
    "stadt" => "Berlin"    // Aus $b
]
*/

// Vergleichsoperatoren
var_dump($a == $b);   // bool(false) - Gleich (gleiche Schlüssel-Wert-Paare)
var_dump($a === $b);  // bool(false) - Identisch (gleiche Schlüssel-Wert-Paare in gleicher Reihenfolge und vom gleichen Typ)
var_dump($a != $b);   // bool(true) - Ungleich
var_dump($a <> $b);   // bool(true) - Alternative Syntax für !=
var_dump($a !== $b);  // bool(true) - Nicht identisch
?>

8.8 Inkrement/Dekrement-Operatoren

Diese Operatoren erhöhen oder verringern einen Wert um 1:

<?php
$a = 5;

// Post-Inkrement
echo $a++;    // 5 (gibt den alten Wert zurück, dann erhöht)
echo $a;      // 6

// Pre-Inkrement
echo ++$a;    // 7 (erhöht zuerst, dann gibt den neuen Wert zurück)

// Post-Dekrement
echo $a--;    // 7 (gibt den alten Wert zurück, dann verringert)
echo $a;      // 6

// Pre-Dekrement
echo --$a;    // 5 (verringert zuerst, dann gibt den neuen Wert zurück)
?>

Diese Operatoren funktionieren auch mit Strings auf besondere Weise:

<?php
$str = 'a';
echo ++$str;    // 'b' (Inkrementiert zum nächsten Buchstaben)

$str = 'z';
echo ++$str;    // 'aa' (nach 'z' kommt 'aa')

$str = 'A9';
echo ++$str;    // 'B0' (inkrementiert den ersten Charakter, der zweite wird zurückgesetzt)
?>

8.9 Bedingte Operatoren

8.9.1 Ternärer Operator

Der ternäre Operator ist eine Kurzform der if-else-Anweisung:

<?php
// Syntax: Bedingung ? Wert_wenn_wahr : Wert_wenn_falsch
$alter = 20;
$status = ($alter >= 18) ? "erwachsen" : "minderjährig";
echo $status;    // "erwachsen"

// Verschachtelte ternäre Operatoren (können unübersichtlich werden)
$status = ($alter < 13) ? "Kind" : (($alter < 18) ? "Teenager" : "Erwachsener");
?>

8.9.2 Null Coalescing Operator (seit PHP 7.0)

Der Null Coalescing Operator (??) prüft, ob der erste Operand existiert und nicht null ist:

<?php
// Vor PHP 7.0 (unsicher wegen Notices)
$username = isset($_GET['user']) ? $_GET['user'] : 'Gast';

// Ab PHP 7.0 (kurz und sicher)
$username = $_GET['user'] ?? 'Gast';

// Verkettung mehrerer Operatoren
$username = $_GET['user'] ?? $_POST['user'] ?? 'Gast';
?>

8.9.3 Null Coalescing Assignment Operator (seit PHP 7.4)

Der Null Coalescing Assignment Operator (??=) weist einen Wert nur zu, wenn die Variable null ist oder nicht existiert:

<?php
// Vor PHP 7.4
$username = $username ?? 'Gast';

// Ab PHP 7.4
$username ??= 'Gast';
?>

8.9.4 Nullsafe Operator (seit PHP 8.0)

Der Nullsafe Operator (?->) ermöglicht den sicheren Zugriff auf Methoden und Eigenschaften, auch wenn ein Objekt null ist:

<?php
// Vor PHP 8.0 (umständlich)
$land = ($benutzer !== null && $benutzer->getAdresse() !== null) 
    ? $benutzer->getAdresse()->getLand() 
    : null;

// Ab PHP 8.0 (elegant und sicher)
$land = $benutzer?->getAdresse()?->getLand();
?>

8.10 Type-Operatoren

8.10.1 Typprüfung mit instanceof

Der instanceof-Operator prüft, ob ein Objekt eine Instanz einer bestimmten Klasse ist:

<?php
class Fahrzeug {}
class Auto extends Fahrzeug {}

$meinAuto = new Auto();

var_dump($meinAuto instanceof Auto);     // bool(true)
var_dump($meinAuto instanceof Fahrzeug); // bool(true)
var_dump($meinAuto instanceof stdClass); // bool(false)
?>

8.11 Ausführungsoperator

Der Ausführungsoperator (Backticks) führt einen Befehl im Betriebssystem aus und gibt dessen Ausgabe zurück:

<?php
// Nicht empfohlen - Sicherheitsrisiko!
$ausgabe = `ls -la`;
echo $ausgabe;

// Bessere Alternative
$ausgabe = shell_exec('ls -la');
// oder
$ausgabe = system('ls -la');
?>

Hinweis: Die Verwendung des Ausführungsoperators kann ein Sicherheitsrisiko darstellen, wenn nicht vertrauenswürdige Eingaben verwendet werden. Verwenden Sie stattdessen Funktionen wie escapeshellcmd() und escapeshellarg(), um Befehle abzusichern.

8.12 Fehlerunterdrückung mit @

Der Fehlerunterdrückungsoperator (@) unterdrückt Fehlermeldungen für den Ausdruck, auf den er angewendet wird:

<?php
// Ohne Fehlerunterdrückung würde dies eine Warnung erzeugen, wenn die Datei nicht existiert
$inhalt = @file_get_contents('nicht_existierende_datei.txt');
?>

Wichtige Hinweise: - Die Verwendung von @ wird generell nicht empfohlen, da sie Probleme verbergen kann - Fehler werden trotzdem erzeugt, aber nicht angezeigt (Performance-Overhead) - Besser ist es, Fehler explizit zu behandeln, z.B. mit try-catch oder Bedingungen

8.13 Operatorpräzedenz und Assoziativität

Die Operatorpräzedenz legt fest, in welcher Reihenfolge Operatoren in einem Ausdruck ausgewertet werden. Operatoren mit höherer Präzedenz werden vor solchen mit niedrigerer Präzedenz ausgewertet.

Die Assoziativität bestimmt, wie Operatoren mit gleicher Präzedenz gruppiert werden (von links nach rechts oder umgekehrt).

<?php
// Präzedenz-Beispiel
echo 5 + 3 * 2;         // 11 (nicht 16), weil * eine höhere Präzedenz hat als +

// Assoziativität-Beispiel (left-to-right)
echo 10 / 5 / 2;        // 1 (nicht 4), weil 10/5 = 2, dann 2/2 = 1

// Verwendung von Klammern zur expliziten Steuerung der Auswertungsreihenfolge
echo (5 + 3) * 2;       // 16
?>

Eine stark vereinfachte Übersicht der Operatorpräzedenz (von hoch nach niedrig):

  1. () (Klammern)
  2. ++, --, ~, (type), @ (Inkrement, Dekrement, Negation, Cast, Fehlerunterdrückung)
  3. ** (Potenzierung)
  4. *, /, % (Multiplikation, Division, Modulo)
  5. +, -, . (Addition, Subtraktion, String-Konkatenation)
  6. <<, >> (Bitweise Verschiebung)
  7. <, <=, >, >=, <=> (Größenvergleiche)
  8. ==, !=, ===, !== (Gleichheitsvergleiche)
  9. & (Bitweises UND)
  10. ^ (Bitweises XOR)
  11. | (Bitweises ODER)
  12. && (Logisches UND)
  13. || (Logisches ODER)
  14. ? : (Ternärer Operator)
  15. =, +=, -=, etc. (Zuweisung)
  16. and (Logisches UND mit niedriger Präzedenz)
  17. xor (Logisches XOR mit niedriger Präzedenz)
  18. or (Logisches ODER mit niedriger Präzedenz)

8.14 Match-Ausdruck (seit PHP 8.0)

Der Match-Ausdruck ist eine moderne Alternative zum switch-Statement, mit einigen wichtigen Unterschieden:

<?php
$status = 2;

// Switch-Statement (traditionell)
switch ($status) {
    case 1:
        $message = "Aktiv";
        break;
    case 2:
        $message = "Inaktiv";
        break;
    default:
        $message = "Unbekannt";
        break;
}

// Match-Ausdruck (seit PHP 8.0)
$message = match ($status) {
    1 => "Aktiv",
    2 => "Inaktiv",
    default => "Unbekannt",
};

// Mehrere Werte pro Arm
$message = match ($status) {
    1, 3, 5 => "Aktiv",
    2, 4, 6 => "Inaktiv",
    default => "Unbekannt",
};

// Ausdrücke als Bedingungen
$message = match (true) {
    $status >= 100 => "Kritisch",
    $status >= 50 => "Warnung",
    $status >= 0 => "Normal",
    default => "Ungültig",
};
?>

Unterschiede zwischen match und switch:

  1. match verwendet strenge Vergleiche (===), während switch lose Vergleiche (==) verwendet
  2. match ist ein Ausdruck und gibt einen Wert zurück, switch ist eine Anweisung
  3. match benötigt keine break-Anweisungen und wertet nur den passenden Arm aus
  4. match benötigt einen default-Arm, wenn nicht alle möglichen Werte abgedeckt sind

8.15 Komplexe Ausdrücke

Ausdrücke in PHP können sehr komplex werden, besonders wenn verschiedene Operatoren kombiniert werden:

<?php
// Komplexer arithmetischer Ausdruck
$result = 5 * (10 + 3) / 2 - 4;

// Komplexer logischer Ausdruck
$isValid = ($age >= 18 && $hasConsent) || ($isSpecialCase && $hasPermission);

// Komplexer Array-Manipulationsausdruck
$filteredData = array_filter(
    array_map(
        fn($item) => $item * 2, 
        array_values($sourceArray)
    ),
    fn($item) => $item > 10
);
?>

8.16 Bewährte Praktiken

  1. Lesbarkeit über Kürze stellen: Verwenden Sie Klammern, um die Absicht klar zu machen, selbst wenn sie nicht unbedingt erforderlich sind.

  2. Vorsicht bei impliziter Typumwandlung: Verwenden Sie === und !== anstelle von == und !=, um unerwartetes Verhalten zu vermeiden.

  3. Komplexe Ausdrücke aufteilen: Teilen Sie komplexe Ausdrücke in mehrere einfachere Anweisungen auf, um die Lesbarkeit zu verbessern.

  4. Vorsicht mit dem Fehlerunterdrückungsoperator: Vermeiden Sie @, da er Probleme verbergen kann. Verwenden Sie stattdessen ordnungsgemäße Fehlerbehandlung.

  5. Nullsafe-Operator statt verschachtelter Prüfungen: In PHP 8.0+ verwenden Sie ?-> anstelle von verschachtelten isset() oder is_null()-Prüfungen.