Stack Overflow from Deep Recursion
debt(d8/e5/b3/t7)
Closest to 'silent in production until users hit it' (d9), but phpstan can flag some recursive patterns and xdebug.max_nesting_level surfaces it in dev, so d8. The crash is uncatchable and depends on input depth, so it usually only manifests under adversarial or unusual inputs.
Closest to 'touches multiple files / significant refactor in one component' (e5). Per quick_fix, converting recursion to iteration with SplStack is a real refactor of the algorithm, not a one-line swap — especially for tree traversal code.
Closest to 'localised tax' (b3). Applies to specific recursive components (parsers, tree walkers), not the whole codebase. The choice to use recursion is local to those functions.
Closest to 'serious trap (contradicts how a similar concept works elsewhere)' (t7). Per misconception, devs expect a catchable exception like in many other languages/runtimes, but PHP segfaults or hits memory_limit uncatchably — directly contradicts the try/catch mental model PHP otherwise supports.
TL;DR
Explanation
PHP's call stack is limited by the OS stack size (typically 8MB on Linux). Deep recursion exhausts it and causes a segfault or memory_limit error — neither is catchable with try/catch. Practical limit is roughly 500–5000 nested calls depending on frame size. Solutions: convert tail-recursive functions to iterative loops, use a trampoline pattern, or process trees iteratively with an explicit stack (SplStack). xdebug.max_nesting_level (default 256) provides an earlier, catchable limit via E_ERROR.
Common Misconception
Why It Matters
Common Mistakes
- Recursive tree traversal without depth limit.
- Not converting obvious tail recursion to iteration.
- Setting xdebug.max_nesting_level too high — delays the crash.
Code Examples
function factorial(int $n): int {
return $n <= 1 ? 1 : $n * factorial($n - 1);
}
factorial(100000); // Segfault
function factorial(int $n): int {
$result = 1;
for ($i = 2; $i <= $n; $i++) $result *= $i;
return $result;
}
// Iterative tree traversal using explicit stack
function traverse(Node $root): void {
$stack = new \SplStack();
$stack->push($root);
while (!$stack->isEmpty()) {
$node = $stack->pop();
process($node);
foreach ($node->children as $child) $stack->push($child);
}
}