debug_backtrace() returns the chain of calls that led to the current line as an array of frames, debug_print_backtrace() prints it, and every exception records one (getTraceAsString()). New in PHP 8.5, fatal_error_backtraces (on by default) adds a trace to true fatal errors such as memory exhaustion, which used to report only a file and a line.
<?php
function exportOrders(string $format, int $rows): string {
debug_print_backtrace(); // who called me, and with what
$out = '';
for ($i = 0; $i < $rows; $i++) $out .= str_repeat('x', 1024);
return $out;
}
function nightlyJob(string $date): void { exportOrders('csv', 1_000_000); }
ini_set('memory_limit', '4M');
nightlyJob('2026-09-23');#0 /home/dev/shop/export.php(8): exportOrders('...', 1000000)
#1 /home/dev/shop/export.php(10): nightlyJob('...')
PHP Fatal error: Allowed memory size of 4194304 bytes exhausted (tried to allocate 2093088
bytes) in /home/dev/shop/export.php on line 5
Stack trace:
#0 /home/dev/shop/export.php(8): exportOrders()
#1 /home/dev/shop/export.php(10): nightlyJob()
#2 {main}The message names the failing line (5). Frame #0 is the innermost call, and export.php(8) means called from line 8; each frame is one step further out, down to {main}. Production settings hide arguments ('...'); the development values show exportOrders('csv', 1000000). Mark a password parameter #[\SensitiveParameter] (Built-In Attributes) to keep it out of every trace.