Symfony AI Mate ist der CLI Assistent für KI gestützte PHP Entwicklung. Seit 0.13 ohne MCP Server, 0.14 bringt neue Tools. Installation, Skills, Setup.
Mehr erfahren
Ein Tag inhouse mit Benjamin Klein für Developer, Tester und Admins. Context Engineering, Harness, ADRs und zwei Hands on Blöcke mit KI Agenten in eurem Setup.
; php.ini für Production
error_reporting = E_ALL
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/app_error.log
zend.exception_ignore_args = On
# Welche php.ini ist geladen und wohin wird geloggt?
php --ini
php -i | grep -E 'error_log|log_errors|display_errors'
# Seit PHP 8.5: nur Werte, die vom Default abweichen
php --ini=diff
# Live mitlesen
tail -f /var/log/php/app_error.log
set_error_handler(function (int $severity, string $message, string $file, int $line): bool {
if (!(error_reporting() & $severity)) {
return false;
}
// Deprecations nur loggen, nicht abbrechen
if ($severity & (E_DEPRECATED | E_USER_DEPRECATED)) {
error_log(sprintf('[deprecated] %s in %s:%d', $message, $file, $line));
return true;
}
throw new ErrorException($message, 0, $severity, $file, $line);
});
set_exception_handler(function (Throwable $e): void {
error_log(sprintf('[%s] %s in %s:%d', $e::class, $e->getMessage(), $e->getFile(), $e->getLine()));
http_response_code(500);
echo 'Es ist ein Fehler aufgetreten.';
});
register_shutdown_function(function (): void {
$error = error_get_last();
if ($error !== null && in_array($error['type'], [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR], true)) {
error_log('[fatal] ' . $error['message']);
}
});
$current = get_error_handler();
if ($current === null) {
// Kein eigener Handler aktiv, PHP Standardverhalten greift
}
# config/packages/prod/monolog.yaml
monolog:
handlers:
main:
type: fingers_crossed
action_level: error
handler: nested
excluded_http_codes: [404, 405]
buffer_size: 50
nested:
type: stream
path: php://stderr
level: debug
formatter: monolog.formatter.json
deprecation:
type: stream
channels: [deprecation]
path: '%kernel.logs_dir%/deprecations.log'
Fatal error: Allowed memory size of 134217728 bytes exhausted in /app/src/Export/CsvExport.php on line 42
Stack trace:
#0 /app/src/Export/CsvExport.php(42): str_repeat('A', 268435456)
#1 /app/src/Controller/ExportController.php(18): App\Export\CsvExport->build()
#2 {main}
$context = stream_context_create([
'stream' => [
'error_mode' => StreamErrorMode::Exception,
],
]);
try {
$handle = fopen('/data/import.csv', 'r', false, $context);
} catch (StreamException $e) {
$first = array_first($e->getErrors());
error_log('Import fehlgeschlagen: ' . $first?->code->name);
}
# Nach dem E2E Lauf in der Pipeline
if [ -s var/log/php_error.log ]; then
echo "PHP Error Log ist nicht leer:"
cat var/log/php_error.log
exit 1
fi
Monolog sends your logs to files, sockets, inboxes, databases and various web services.
Symfony AI Mate ist der CLI Assistent für KI gestützte PHP Entwicklung. Seit 0.13 ohne MCP Server, 0.14 bringt neue Tools. Installation, Skills, Setup.
Mehr erfahren
Wir sind Experten für PHP und helfen Ihnen, Ihre digitalen Herausforderungen zu meistern. Unser erfahrenes Team unterstützt Sie bei PHP Updates, PHP Refactoring und berät Sie remote zu allen Fragen rund um PHP. Mit unseren vollautomatischen CI/CD Deployments und einer robusten Docker-Infrastruktur bringen wir Ihre PHP-Projekte auf das nächste Level. Vertrauen Sie auf unsere Expertise für zuverlässige und skalierbare PHP-Lösungen.
Du setzt in der php.ini log_errors = On und error_log auf einen absoluten Pfad, auf den PHP schreiben darf. Dazu kommen error_reporting = E_ALL und für Production display_errors = Off. Nach einem Neustart von PHP FPM oder dem Webserver greift die Konfiguration. Mit php --ini prüfst du, welche php.ini wirklich geladen ist, denn CLI und Webserver nutzen oft verschiedene Dateien.
Den Pfad verraten php -i oder ini_get('error_log'). Ist kein Pfad gesetzt, schreibt PHP FPM in das Log des Pools, Apache mit mod_php in sein eigenes Error Log und die CLI auf stderr. In Containern und mit FrankenPHP landen Fehler meist in stdout und stderr. Seit PHP 8.5 zeigt php --ini=diff alle Werte, die vom Standard abweichen.
Die wichtigste Neuerung sind Stack Traces für Fatal Errors. Die Direktive fatal_error_backtraces ist standardmäßig aktiv und hängt die komplette Aufrufkette an Meldungen wie Speicher oder Zeitlimit an. Sensible Parameter bleiben dabei verborgen. Dazu kommen get_error_handler(), get_exception_handler() und php --ini=diff. Log Parser solltest du prüfen, weil Fatal Errors jetzt mehrzeilig sind.
PHP 8.6 führt strukturiertes Error Handling für Streams ein. Über einen Stream Context lassen sich fopen() und verwandte Funktionen so einstellen, dass sie Exceptions werfen oder Fehler still speichern. Statt Warning Texte zu parsen, bekommst du typisierte Codes über das Enum StreamErrorCode. Das Standardverhalten bleibt gleich, bestehender Code läuft also weiter wie bisher.
Bewährt haben sich error_reporting = E_ALL, display_errors = Off, log_errors = On und ein absoluter error_log Pfad mit Log Rotation. zend.exception_ignore_args = On hält Argumente aus Stack Traces heraus. Fatal Error Backtraces bleiben aktiv, landen aber nur im Log. Ergänzend schickt Monolog Errors strukturiert an Sentry, und Grafana zeigt die Fehlerrate über die Zeit.
Fehlermeldungen verraten Dateipfade, Datenbanknamen, SQL Abfragen und manchmal Zugangsdaten. Diese Informationen helfen Angreifern, die Anwendung gezielt anzugreifen. Außerdem zerstört eine Fehlermeldung mitten im HTML das Layout und verunsichert Besucher. Besser ist eine neutrale Fehlerseite mit Referenz ID. Die Details stehen im Error Log, wo nur das Team sie sieht.
Häufige Ursachen: log_errors ist aus, der PHP Prozess darf nicht in die Datei schreiben, die CLI nutzt eine andere php.ini, oder ein eigener Error Handler gibt true zurück und schluckt den Fehler. Auch der @ Operator unterdrückt Meldungen. Prüfe mit php -i den aktiven Pfad und teste mit trigger_error und E_USER_WARNING, ob überhaupt etwas ankommt.
Das Error Log ist das Ziel, in das PHP selbst Fehler schreibt. Die Funktion error_log() ist ein Weg, eigene Meldungen dort hineinzuschreiben, oder per Parameter in eine andere Datei. Für größere Anwendungen reicht error_log() selten. Ein Logger nach PSR 3 wie Monolog bietet Level, Kanäle, Kontext Daten und Handler für verschiedene Ziele.
Markiere sensible Parameter in Funktionssignaturen mit dem Attribut #[\SensitiveParameter]. PHP ersetzt ihren Wert in Stack Traces dann durch einen Platzhalter. Zusätzlich sorgt zend.exception_ignore_args = On dafür, dass Argumente gar nicht erst in Traces auftauchen. Bei eigenen Log Meldungen gilt: keine Request Bodies, Tokens oder vollständigen Nutzerdaten loggen.
Ohne Rotation wächst es, bis die Festplatte voll ist, und dann schreibt PHP gar nichts mehr. Richte logrotate ein, etwa täglich mit Komprimierung und einer festen Anzahl alter Dateien. Wichtiger als die Größe ist der Inhalt: Tausende gleiche Warnings sind ein Zeichen für Bugs, die behoben gehören, nicht für zu wenig Speicherplatz.
Ja. Deprecations zeigen genau die Stellen, die mit dem nächsten Major Release brechen. Loggst du sie in einem eigenen Kanal, stören sie den Alarm für echte Fehler nicht. Vor einem Upgrade wertest du diesen Kanal aus und gibst die Liste an Rector oder PHPCompatibility weiter. So wird das Upgrade planbar statt überraschend.
Entfernen. E_STRICT wird seit PHP 8.0 nicht mehr ausgelöst, die Konstante ist seit PHP 8.4 deprecated und soll mit PHP 9 verschwinden. Ein error_reporting mit E_ALL | E_STRICT erzeugt heute selbst eine Deprecation. E_ALL deckt alles ab, was du brauchst. Rector und PHPCompatibility finden solche Stellen automatisch im Code.
Ja, und das funktioniert gut, weil das Log beschreibt, was wirklich passiert ist. In Symfony Projekten gibt Symfony AI Mate Coding Agents Werkzeuge, um Monolog Logs zu durchsuchen und nach Level oder Kanal zu filtern. Wir lassen Agents dabei Logs aus der lokalen Entwicklung mit anonymisierten Testdaten lesen. So bleibt der Datenschutz gewahrt und der Fehler trotzdem nachvollziehbar.