Um PHP-Code effektiv zu entwickeln und zu optimieren, ist ein grundlegendes Verständnis der PHP-Laufzeitumgebung essentiell. Dieser Abschnitt erläutert, wie PHP-Code ausgeführt wird, wie der Lebenszyklus einer PHP-Anfrage aussieht und welche Kernmechanismen dabei eine Rolle spielen.
PHP ist eine interpretierte Sprache, was bedeutet, dass der Code zur Laufzeit in Maschinensprache übersetzt und ausgeführt wird – im Gegensatz zu kompilierten Sprachen wie C++, bei denen dieser Prozess vor der Ausführung stattfindet.
Die Ausführung eines PHP-Skripts durchläuft mehrere Phasen:
<?php
// Ein einfaches Beispiel, um den Ausführungsprozess zu verstehen
$a = 1;
$b = 2;
echo $a + $b; // Diese Operation wird in Bytecode umgewandelt und dann ausgeführt
?>Das Herzstück der PHP-Laufzeitumgebung ist die Zend Engine, die für die Interpretation und Ausführung des PHP-Codes verantwortlich ist.
| Version | PHP-Version | Hauptverbesserungen |
|---|---|---|
| Zend Engine 1 | PHP 4 | Erste Version mit virtuellem Maschinen-Konzept |
| Zend Engine 2 | PHP 5 | Verbessertes OOP-Modell, Exceptions |
| Zend Engine 3 | PHP 7 | Optimierte Speichernutzung, ~2x schneller |
| Zend Engine 4 | PHP 8 | JIT-Kompilierung, Referenzzählung, verbesserte Typinferenz |
PHP kann in verschiedenen Modi ausgeführt werden, die unterschiedliche Einsatzzwecke und Leistungscharakteristiken haben:
# Ausführung eines PHP-Skripts über die Kommandozeile
php script.php
# Ausführung eines einzelnen PHP-Befehls
php -r 'echo "Hallo Welt!";'Der CLI-Modus ist für Kommandozeilen-Tools, Cron-Jobs und Skripte gedacht, die nicht über einen Webserver ausgeführt werden müssen.
Im Webserver-Kontext gibt es verschiedene Methoden, PHP-Code auszuführen:
Modul für den Webserver (z.B. mod_php für Apache): PHP wird direkt als Modul in den Webserver integriert, wodurch es effizient und einfach zu konfigurieren ist, aber weniger isoliert läuft.
FastCGI-Prozess (PHP-FPM): PHP läuft als separater Prozess und kommuniziert über das FastCGI-Protokoll mit dem Webserver. Dies bietet bessere Isolation und Skalierbarkeit.
CGI (Common Gateway Interface): Der älteste Modus, bei dem für jede Anfrage ein neuer PHP-Prozess gestartet wird. Ineffizient für hohe Last, aber mit der höchsten Isolation.
Seit PHP 5.4 gibt es einen eingebauten Webserver für die Entwicklung:
# Startet einen Webserver auf Port 8000 mit dem aktuellen Verzeichnis als Wurzel
php -S localhost:8000Dieser Server ist nur für die Entwicklungsphase gedacht und sollte nicht in Produktionsumgebungen eingesetzt werden.
Wenn eine Anfrage an ein PHP-Skript gesendet wird, durchläuft diese einen definierten Lebenszyklus:
Hier ein beispielhafter Ablauf einer Webanfrage:
[Browser] --- HTTP-Anfrage ---> [Webserver] ---> [PHP-Interpreter]
| |
| PHP-Verarbeitung |
| Datenbanken |
| Dateisystem |
| v
[Browser] <--- HTTP-Antwort --- [Webserver] <--- [PHP-Ausgabe]
Ein wichtiger Bestandteil moderner PHP-Umgebungen ist OPcache, der den kompilierten Bytecode zwischenspeichert, um wiederholte Kompilierungen zu vermeiden:
; Aktivierung von OPcache in php.ini
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.validate_timestamps=1
opcache.revalidate_freq=2Bei jedem Request muss PHP den Code neu lexen, parsen und kompilieren, bevor er ausgeführt werden kann - ein rechenintensiver Prozess.
Nach der ersten Ausführung wird der kompilierte Bytecode im Shared Memory gespeichert. Bei nachfolgenden Anfragen kann PHP direkt auf diesen Bytecode zugreifen und die Phasen Lexing, Parsing und Kompilierung überspringen.
Ohne OPcache: PHP-Code -> Lexing -> Parsing -> Kompilierung -> Ausführung
Mit OPcache: PHP-Code -> [Cache-Prüfung] -> Ausführung (wenn im Cache)
OPcache kann die Performance um das 2- bis 5-fache verbessern, abhängig von der Komplexität des Codes.
Mit PHP 8 wurde ein Just-In-Time (JIT) Compiler eingeführt, der den PHP-Bytecode zur Laufzeit in nativen Maschinencode umwandeln kann. Dies führt zu signifikanten Performance-Verbesserungen bei CPU-intensiven Aufgaben:
; Aktivierung von JIT in php.ini
opcache.enable=1
opcache.jit_buffer_size=100M
opcache.jit=1255Der JIT-Compiler in PHP 8 bietet verschiedene Modi, die über die
Einstellung opcache.jit konfiguriert werden können:
JIT-Kompilierung ist besonders vorteilhaft für: - Mathematische Berechnungen - Bildverarbeitung - Algorithmen mit vielen Schleifen und Berechnungen - CPU-intensive Hintergrundprozesse
Bei typischen Web-Anwendungen, die durch I/O-Operationen (Datenbank, Dateisystem) begrenzt sind, kann der Vorteil geringer ausfallen.
PHP verwendet ein automatisches Speichermanagement mit Referenzzählung und einem zyklischen Garbage Collector:
Jeder Variable wird ein Referenzzähler zugewiesen. Wenn der Zähler auf 0 fällt, wird der Speicher freigegeben:
<?php
$a = "Hallo"; // Referenzzähler für den String "Hallo" ist 1
$b = $a; // Referenzzähler erhöht sich auf 2
unset($a); // Referenzzähler sinkt auf 1
unset($b); // Referenzzähler sinkt auf 0, Speicher wird freigegeben
?>Bei zirkulären Referenzen kann die Referenzzählung allein nicht erkennen, wann Speicher freigegeben werden kann:
<?php
$a = new stdClass();
$b = new stdClass();
$a->ref = $b; // $a referenziert $b
$b->ref = $a; // $b referenziert $a
unset($a); // Referenzzähler für $a ist noch nicht 0 (wegen $b->ref)
unset($b); // Referenzzähler für $b ist noch nicht 0 (wegen der Referenz in $a)
// Hier würde ohne zyklischen Garbage Collector ein Speicherleck entstehen
?>Der zyklische Garbage Collector identifiziert solche “Referenzinseln” und gibt sie frei, wenn sie nicht mehr erreichbar sind.
PHP stellt verschiedene vordefinierte Variablen bereit, die im gesamten Skript verfügbar sind:
<?php
// Server- und Anfrageinformationen
echo $_SERVER['HTTP_USER_AGENT']; // Browser-Informationen
// URL-Parameter
$id = $_GET['id']; // Parameter aus der URL-Abfrage
// Formulardaten
$username = $_POST['username']; // Über POST übermittelte Formulardaten
// Cookies
$lastVisit = $_COOKIE['last_visit']; // Gespeicherte Cookies
// Session-Variablen
$_SESSION['user_id'] = 123; // In der Session gespeicherte Daten
// Umgebungsvariablen
$path = $_ENV['PATH']; // Umgebungsvariablen des Servers
// Dateien
$uploadedFile = $_FILES['userfile']; // Hochgeladene Dateien
?>Die PHP-Laufzeitumgebung kann über verschiedene Methoden konfiguriert werden:
Die zentrale Konfigurationsdatei für PHP:
; Beispiel für php.ini-Einstellungen
max_execution_time = 30
memory_limit = 128M
error_reporting = E_ALL & ~E_DEPRECATED
display_errors = OffFür Apache-Webserver kann PHP auch über .htaccess-Dateien konfiguriert werden:
# PHP-Einstellungen in .htaccess
php_value memory_limit 256M
php_flag display_errors OnViele Einstellungen können auch direkt im PHP-Code geändert werden:
<?php
// PHP-Einstellungen im Code ändern
ini_set('display_errors', '1');
ini_set('memory_limit', '512M');
// Aktuelle Einstellung abrufen
echo ini_get('max_execution_time');
?>Die Einstellungen werden in dieser Reihenfolge geladen (wobei spätere Quellen frühere überschreiben können):
PHP-Erweiterungen fügen der Laufzeitumgebung zusätzliche Funktionalitäten hinzu:
<?php
// Beispiel für die Verwendung von Erweiterungen
if (extension_loaded('gd')) {
// GD-Bibliothek für Bildbearbeitung verwenden
$image = imagecreatefrompng('input.png');
// ...
}
if (extension_loaded('pdo_mysql')) {
// PDO für MySQL-Datenbankverbindungen verwenden
$pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
// ...
}
?><?php
// Überprüfen, ob eine Erweiterung geladen ist
if (!extension_loaded('mysqli')) {
die('MySQLi-Erweiterung ist nicht verfügbar!');
}
// Alle geladenen Erweiterungen anzeigen
print_r(get_loaded_extensions());
// Dynamisches Laden einer Erweiterung (wenn vom Server erlaubt)
if (function_exists('dl')) {
dl('extension_name.so'); // Linux/Unix
// oder
dl('extension_name.dll'); // Windows
}
?>PHP bietet zwei verschiedene Builds:
<?php
// Überprüfen, ob PHP thread-safe kompiliert wurde
echo PHP_ZTS ? 'Thread-Safe' : 'Non-Thread-Safe';
?>Für die meisten modernen Setups (PHP-FPM, FastCGI) ist die NTS-Version empfehlenswert, da sie eine bessere Performance bietet und keine Thread-Sicherheit benötigt.
Die PHP-Laufzeitumgebung verhält sich je nach Kontext unterschiedlich:
<?php
// Überprüfen, ob das Skript im CLI-Modus läuft
if (php_sapi_name() === 'cli') {
echo "Dieses Skript läuft auf der Kommandozeile\n";
// CLI-spezifische Aktionen
echo "Argumente: " . implode(', ', array_slice($argv, 1)) . "\n";
}
?><?php
// Webspezifische Aktionen
if (php_sapi_name() !== 'cli') {
header('Content-Type: text/html; charset=utf-8');
session_start();
// ...
}
?>