A category tree walker that recursed to a depth of eleven in development and to two hundred in production, on data nobody had constrained.
// before: recursion, and a stack overflow at ~9,000
private function walk(Category $c, array $acc = []): array
{
foreach ($c->children as $child) {
$acc = $this->walk($child, $acc);
}
return [...$acc, $c];
}
// after: an explicit stack, and a depth guard
$stack = [$root];
while ($node = array_pop($stack)) {
/* ... */
array_push($stack, ...$node->children);
}
The production data had a cycle — a category that was its own ancestor, created by an import in 2022 — so the depth was unbounded rather than deep. The explicit stack turns the overflow into a loop that never ends, which is not better, so the actual fix was a visited set and a constraint on the table.