Every guide to a PHP problem starts with "turn on display_errors". On a live site that prints your file paths, your framework, sometimes your database name, to anyone who can make the page error - including whoever is trying to.
The right settings for live
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/mysite-error.log
error_reporting = E_ALL & ~E_DEPRECATED
E_ALL without deprecations keeps the log readable on an older codebase while still recording everything that is actually wrong.
Watch it while you reproduce
tail -f /var/log/php/mysite-error.log
Leave that running and load the broken page. You get the same information display_errors would have shown, at the same moment, without a visitor ever seeing it.
If you must see it in the browser
Show it to yourself only, by address:
if ((@$_SERVER["REMOTE_ADDR"] ?? "") === "YOUR.IP.HERE") {
ini_set("display_errors", "1");
error_reporting(E_ALL);
}
Put that behind a check you cannot forget to remove - a constant in a config file that is not deployed, not a line commented out. A commented-out line gets uncommented.
A log that grows too fast
sort /var/log/php/mysite-error.log | uniq -c | sort -rn | head -5
One notice on every request writes gigabytes in a day. The top line of that output is nearly always the whole problem.
Turn deprecations back on for a day before a PHP upgrade. They are the warnings that become errors in the next version, and reading them early is the cheapest possible preparation.