getTraceAsString()
Learn the PHP getTraceAsString() method: how it returns an exception's stack trace as a string, how to read the output, and how to log or display it.
What getTraceAsString() Does
getTraceAsString() is a method available on every PHP exception (any class that
implements Throwable — Exception, Error, and their subclasses). It returns the
stack trace — the chain of function and method calls that were active at the moment the
exception was thrown — formatted as a single human-readable string.
The stack trace answers the question "how did execution get here?" When something throws
deep inside your code, the message alone (getMessage()) tells you what went wrong, but
the trace tells you the exact path of calls that led to it. That makes it the single most
useful piece of information when debugging an error you can't easily reproduce.
getTraceAsString() is the string version of getTrace(), which
returns the same information as a structured array. Use getTrace() when you need to inspect
individual frames programmatically; use getTraceAsString() when you just want something to
log or print.
Syntax
public Throwable::getTraceAsString(): stringIt takes no arguments and is final on the base Exception and Error classes, so it
always returns PHP's standard trace format. You call it on a caught exception object inside a
catch block:
<?php
try {
// Code that may throw an exception
} catch (Throwable $e) {
$trace = $e->getTraceAsString();
}Catching Throwable (rather than only Exception) means you also handle Error objects
such as TypeError and DivisionByZeroError. See the Exception
chapter for the full hierarchy.
A Complete, Runnable Example
This script throws an exception two levels deep so you can see what the trace string actually looks like:
<?php
function loadUser(int $id): array
{
throw new InvalidArgumentException("No user with id $id");
}
function handleRequest(): void
{
loadUser(42);
}
try {
handleRequest();
} catch (Throwable $e) {
echo $e->getTraceAsString();
}Output:
#0 /app/index.php(10): loadUser(42)
#1 /app/index.php(14): handleRequest()
#2 {main}Reading the Output
Each line is one frame in the call stack, listed innermost first:
#0,#1, … — the frame number.#0is the call that was running when the exception was thrown; higher numbers are the callers above it./app/index.php(10)— the file and line number of the call site.loadUser(42)— the function or method that was called, with its arguments. Long string arguments are truncated (e.g.'/etc/app/missin...') to keep the trace readable.#2 {main}— the special final frame marking the top-level script (the global scope).
The throw site itself (the exact file and line where throw ran) is not in this string —
it lives in getFile() and getLine().
Examples
Example 1: Logging the Trace to a File
In production you rarely want to show a trace to the user — you log it for later analysis. Combine the message, file, and line with the trace for a complete record:
<?php
try {
// Code that may throw an exception
} catch (Throwable $e) {
$entry = sprintf(
"[%s] %s in %s:%d\n%s\n\n",
date('Y-m-d H:i:s'),
$e->getMessage(),
$e->getFile(),
$e->getLine(),
$e->getTraceAsString()
);
file_put_contents('/path/to/app.log', $entry, FILE_APPEND | LOCK_EX);
}LOCK_EX prevents two simultaneous requests from interleaving their log entries. For real
applications a logging library such as Monolog is preferable, but the underlying data is the
same string you get here.
Example 2: Displaying the Trace in the Browser (Development Only)
When working locally it can be handy to print the trace straight to the page. Wrap it in
<pre> so the line breaks are preserved, and escape it so trace contents can't inject HTML:
<?php
try {
// Code that may throw an exception
} catch (Throwable $e) {
echo '<pre>' . htmlspecialchars($e->getTraceAsString()) . '</pre>';
}Never expose traces to end users in production — they reveal file paths, code structure, and sometimes argument values that help attackers. Gate this behind an environment check.
Example 3: Preserving the Trace Across Re-throws
When you catch a low-level exception and re-throw a more meaningful one, pass the original as the previous exception so its trace isn't lost:
<?php
try {
// some database call that throws PDOException
} catch (PDOException $e) {
throw new RuntimeException('Could not load the report', 0, $e);
}The new RuntimeException has its own trace, while
getPrevious() gives you back the original exception (and its
getTraceAsString()). PHP's default uncaught-exception handler prints both, chained.
Common Gotchas
- The trace describes the throw point, not the catch point. It is fixed at the moment the
exception is constructed, so calling
getTraceAsString()later still shows where the exception originated, not where you handled it. - Arguments may be truncated or hidden. Long strings are shortened; with the
zend.exception_ignore_argsINI setting enabled (the default in many production setups), argument values are omitted entirely for security. - It returns a string, never
null. Even for an exception thrown at the top level you get at least the#0 {main}frame.
Related Methods
getTrace()— the same data as a structured array.getMessage()— the human-readable error message.getCode()— the exception's numeric code.getPrevious()— the chained previous exception.set-exception-handler()— handle uncaught exceptions globally.
Conclusion
getTraceAsString() turns an exception's call stack into a compact, loggable string, making
it one of the most valuable tools for diagnosing errors in PHP. Pair it with getMessage(),
getFile(), and getLine() to capture a full picture of every failure, log it rather than
showing it to users in production, and preserve the chain with getPrevious() whenever you
re-throw.