PHP Performance Optimierung Tipps
PHP Performance Optimierung
Langsame PHP-Anwendungen frustrieren Benutzer und schaden dem SEO-Ranking. Diese Anleitung zeigt bewährte Methoden, um PHP-Code zu optimieren, Caching einzurichten und Datenbankabfragen zu beschleunigen.
PHP-Version aktualisieren
Der einfachste Performance-Gewinn: PHP aktuell halten.
| PHP Version | Performance vs. 5.6 | Status |
|---|---|---|
| PHP 5.6 | Baseline | ❌ EOL |
| PHP 7.4 | ~3x schneller | ❌ EOL |
| PHP 8.0 | ~3.5x schneller | ⚠️ Security only |
| PHP 8.1 | ~3.7x schneller | ⚠️ Security only |
| PHP 8.2 | ~4x schneller | ✅ Aktiv |
| PHP 8.3 | ~4.2x schneller | ✅ Aktuell |
# PHP-Version prüfen
php -v
# Bei Ubuntu/Debian upgraden
sudo apt install php8.3 php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml
OPcache aktivieren und optimieren
OPcache speichert vorkompiliertes PHP im Speicher:
# php.ini Einstellungen
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=30000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
opcache.save_comments=1
# Für Produktion (keine Änderungen erwartet)
opcache.validate_timestamps=0
⚠️ Wichtig: Bei validate_timestamps=0 müssen Sie OPcache nach Änderungen manuell leeren oder PHP-FPM neu starten.
OPcache-Status prüfen
<?php
// opcache-status.php
$status = opcache_get_status();
echo "Memory used: " . round($status['memory_usage']['used_memory'] / 1024 / 1024, 2) . " MB\n";
echo "Memory free: " . round($status['memory_usage']['free_memory'] / 1024 / 1024, 2) . " MB\n";
echo "Cached scripts: " . $status['opcache_statistics']['num_cached_scripts'] . "\n";
echo "Hit rate: " . round($status['opcache_statistics']['opcache_hit_rate'], 2) . "%\n";
Code-Optimierung
Schleifen optimieren
<?php
// ❌ Schlecht: count() wird bei jeder Iteration aufgerufen
for ($i = 0; $i < count($array); $i++) {
// ...
}
// ✅ Gut: count() nur einmal
$length = count($array);
for ($i = 0; $i < $length; $i++) {
// ...
}
// ✅ Noch besser: foreach verwenden
foreach ($array as $item) {
// ...
}
String-Operationen
<?php
// ❌ Schlecht: Konkatenation in Schleife
$html = '';
foreach ($items as $item) {
$html .= "<li>{$item}</li>";
}
// ✅ Gut: Array und implode
$parts = [];
foreach ($items as $item) {
$parts[] = "<li>{$item}</li>";
}
$html = implode('', $parts);
// ✅ Oder: Output Buffering
ob_start();
foreach ($items as $item) {
echo "<li>{$item}</li>";
}
$html = ob_get_clean();
Variablen und Speicher
<?php
// ❌ Unnötige Variablen
$data = file_get_contents('large-file.json');
$decoded = json_decode($data, true);
$filtered = array_filter($decoded, fn($item) => $item['active']);
$result = array_map(fn($item) => $item['name'], $filtered);
// ✅ Speicher freigeben
$data = file_get_contents('large-file.json');
$decoded = json_decode($data, true);
unset($data); // Speicher freigeben
$filtered = array_filter($decoded, fn($item) => $item['active']);
unset($decoded);
$result = array_map(fn($item) => $item['name'], $filtered);
unset($filtered);
Funktionen vs. Sprachkonstrukte
<?php
// ❌ Langsamer: Funktion
isset($array['key']) ? $array['key'] : 'default';
// ✅ Schneller: Null-Coalescing Operator (PHP 7+)
$array['key'] ?? 'default';
// ❌ Langsamer
if (empty($var)) { }
// ✅ Schneller (wenn Typ bekannt)
if ($var === '' || $var === null) { }
Datenbank-Optimierung
Prepared Statements (auch schneller!)
<?php
// ❌ Schlecht und unsicher
$sql = "SELECT * FROM users WHERE id = " . $userId;
$result = $db->query($sql);
// ✅ Gut: Prepared Statement
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
$stmt->execute([$userId]);
$result = $stmt->fetch();
N+1 Problem vermeiden
<?php
// ❌ N+1 Problem: 1 Query + N Queries
$users = $db->query("SELECT * FROM users")->fetchAll();
foreach ($users as $user) {
$orders = $db->query("SELECT * FROM orders WHERE user_id = {$user['id']}")->fetchAll();
}
// ✅ Mit JOIN: 1 Query
$sql = "SELECT u.*, o.* FROM users u LEFT JOIN orders o ON u.id = o.user_id";
$results = $db->query($sql)->fetchAll();
// ✅ Oder: 2 Queries mit IN
$users = $db->query("SELECT * FROM users")->fetchAll();
$userIds = array_column($users, 'id');
$orders = $db->query("SELECT * FROM orders WHERE user_id IN (" . implode(',', $userIds) . ")")->fetchAll();
Nur benötigte Spalten laden
<?php
// ❌ Alles laden
$sql = "SELECT * FROM products";
// ✅ Nur was nötig ist
$sql = "SELECT id, name, price FROM products";
Caching implementieren
APCu für Anwendungsdaten
<?php
// APCu für einfaches Caching
function getExpensiveData($key) {
$cacheKey = 'data_' . $key;
// Aus Cache lesen
$cached = apcu_fetch($cacheKey, $success);
if ($success) {
return $cached;
}
// Daten berechnen
$data = expensiveOperation($key);
// In Cache speichern (1 Stunde)
apcu_store($cacheKey, $data, 3600);
return $data;
}
Redis für verteiltes Caching
<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
function getCachedData($key) {
global $redis;
$cached = $redis->get($key);
if ($cached !== false) {
return json_decode($cached, true);
}
$data = expensiveOperation($key);
$redis->setex($key, 3600, json_encode($data));
return $data;
}
PHP-FPM Optimierung
# /etc/php/8.3/fpm/pool.d/www.conf
[www]
; Process Manager
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 500
; Bei viel RAM: ondemand oder static testen
; pm = ondemand
; pm.process_idle_timeout = 10s
Profiling und Debugging
Ausführungszeit messen
<?php
$start = microtime(true);
// Code hier
$end = microtime(true);
echo "Ausführungszeit: " . ($end - $start) . " Sekunden";
Xdebug Profiling
# php.ini
xdebug.mode=profile
xdebug.output_dir=/tmp/xdebug
xdebug.start_with_request=trigger
# Dann URL mit ?XDEBUG_PROFILE aufrufen
# Cachegrind-Datei mit KCachegrind oder Webgrind analysieren
Quick Wins Checkliste
- ☐ PHP 8.2+ verwenden
- ☐ OPcache aktiviert und konfiguriert
- ☐ Unnötige Extensions deaktiviert
- ☐ Prepared Statements verwenden
- ☐ N+1 Queries eliminiert
- ☐ Output Caching implementiert
- ☐ Session-Handler optimiert (Redis/Memcached)
- ☐ Autoloader optimiert (Composer dump-autoload -o)
Weitere Hilfe
- 📖 PHP OPcache Dokumentation
- 📧 E-Mail: support@enjyn.de