max_execution_time & set_time_limit()
debt(d3/e3/b3/t7)
Closest to 'default linter catches the common case' (d3). The term's detection_hints list phpcs and phpstan as tools that can catch `set_time_limit(0)` patterns. These are commonly configured PHP tools that would flag the obvious misuse, though they won't catch the subtler misconception about CPU vs wall-clock time.
Closest to 'simple parameterised fix' (e3). The quick_fix indicates moving operations to CLI/queue workers and calling set_time_limit(60) per iteration in loops. This is a pattern-based refactor within the same component—not a one-liner, but also not cross-cutting architectural work.
Closest to 'localised tax' (b3). The term applies to web, cli, and queue-worker contexts, but the fix pattern (using queue workers for long operations) is a localized architectural choice. It doesn't impose a persistent productivity tax across the codebase—once you establish the pattern of using background jobs, individual features follow it.
Closest to 'serious trap' (t7). The misconception explicitly states that developers wrongly assume max_execution_time is wall-clock time when it only counts CPU time. This directly contradicts how similar timeout concepts work in other systems (e.g., HTTP timeouts, database timeouts are all wall-clock). A script waiting for I/O can run indefinitely, which violates reasonable developer expectations.
TL;DR
Explanation
max_execution_time (default 30s) measures CPU time consumed by the PHP process, not wall-clock time. Blocking I/O (sleep, DB queries, HTTP requests) does NOT count. This means a script making many slow DB calls can run for minutes without hitting the limit. set_time_limit(N) resets the timer from the current point. CLI scripts have max_execution_time=0 (unlimited) by default. The fatal error it produces is uncatchable. For long operations: use background jobs/queues, call set_time_limit() in loops, or use CLI with time limits managed by the OS.
Common Misconception
Why It Matters
Common Mistakes
- Using set_time_limit(0) in web requests — allows infinite execution.
- Assuming max_execution_time protects against slow DB queries.
- Not using background jobs for operations known to exceed 30s.
Code Examples
// In a web controller:
set_time_limit(0); // Disable limit for 'safety'
foreach ($millionRows as $row) { processRow($row); }
// In a CLI command or queue worker:
set_time_limit(3600); // 1 hour for this operation
// Reset per chunk to avoid single-chunk timeout:
foreach (array_chunk($rows, 500) as $chunk) {
set_time_limit(60); // 60s per chunk
processChunk($chunk);
}