← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

PHP CLI & Command-Line Scripts

PHP PHP 5.0+ Beginner
debt(d7/e5/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints list phpstan and symfony-console, but neither will automatically catch missing SIGTERM handlers, improper exit codes, or memory leaks in long-running loops without careful custom configuration. The code_pattern field notes 'automated: no', confirming these issues surface only under review or when the script is actually run in production-like conditions.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix spans several concerns: adding proper IO handling, exit codes, explicit memory/time limits, and pcntl_signal() handlers. While each fix individually may be small, correcting a CLI script that misuses HTTP superglobals, leaks memory in long loops, and lacks graceful shutdown handling requires touching multiple parts of the script and its surrounding infrastructure (cron config, CI pipeline expectations), landing this at e5.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). The applies_to contexts are cli and queue-worker — not the entire codebase — but long-running queue workers are often load-bearing components. Misconfigurations (missing limits, no SIGTERM handling, wrong exit codes) create ongoing maintenance overhead every time a new CLI script or worker is added, making this a persistent tax on those work streams rather than a one-off fix.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception is explicit: developers assume PHP CLI shares the same php.ini as the web server, but it uses a separate configuration with different defaults for memory_limit, max_execution_time, and extensions. Additionally, CLI does not reset state between iterations, contradicting the web-request mental model most PHP developers carry. This directly contradicts how the web PHP process works, qualifying as a t7 trap that contradicts a familiar analogous concept.

About DEBT scoring →

Also Known As

PHP command line php cli CLI scripts

TL;DR

Running PHP from the command line for scripts, queue workers, cron jobs, and interactive tools — a distinct execution context from web requests.

Explanation

PHP CLI runs without a web server, with no request timeout, unlimited execution time by default, and access to stdin/stdout/stderr via STDIN, STDOUT, and STDERR constants. Arguments are available via $argv/$argc. Key differences from web PHP: no $_GET/$_POST/$_SERVER HTTP keys, different error output (stderr), and no output buffering by default. Use PHP CLI for: queue workers (long-running), scheduled tasks (cron), database migrations, and build scripts. Symfony Console and Laravel Artisan provide command frameworks with argument parsing, progress bars, and table output. Always handle signals (pcntl_signal) in long-running workers for graceful shutdown. Long-running CLI processes must actively manage memory — objects and references persist across iterations unlike web requests.

Common Misconception

PHP CLI scripts share the same configuration as the web server PHP process. PHP CLI uses a separate php.ini — memory_limit, max_execution_time, and extension settings often differ. CLI also does not reset state between iterations like web requests, which means memory usage and static variables persist in long-running scripts.

Why It Matters

PHP CLI enables running scripts, cron jobs, and build tools without a web server — it has different php.ini defaults, no request timeout, and access to stdin/stdout/stderr making it ideal for automation. Misunderstanding CLI behaviour leads to memory leaks, silent failures in CI, and unstable workers.

Common Mistakes

  • Not setting the correct shebang (#!/usr/bin/env php) for executable PHP scripts.
  • Using $_SERVER['REQUEST_URI'] or other HTTP superglobals in CLI scripts — they are not populated.
  • Not handling exit codes — a CLI script that exits with 0 on error confuses CI pipelines.
  • Ignoring that CLI has no memory or time limits by default — add them explicitly for long-running tasks.
  • Running long loops without freeing memory (e.g. ORM entities, large arrays) — leads to memory leaks and crashes.

Code Examples

✗ Vulnerable
// CLI script with no exit code handling — CI can't detect failure:
<?php
try {
    runImport();
} catch (Exception $e) {
    echo $e->getMessage(); // Prints error but exits with 0 — CI thinks success
}
// Fix: exit(1) on failure
✓ Fixed
#!/usr/bin/env php
<?php
// Guard: must not run via web
if (php_sapi_name() !== 'cli') {
    fwrite(STDERR, "CLI only.\n"); exit(1);
}

// Parse arguments
$opts   = getopt('u:v', ['user:', 'verbose']);
$userId = $opts['u'] ?? $opts['user'] ?? null;
$verbose = isset($opts['v']) || isset($opts['verbose']);

if (!$userId) {
    fwrite(STDERR, "Usage: php script.php -u <user_id>\n"); exit(1);
}

fwrite(STDOUT, "Processing user $userId\n");

// Exit codes: 0 = success, non-zero = error
exit(0);

Added 15 Mar 2026
Edited 16 Apr 2026
Views 51
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 2 pings F 1 ping S 5 pings S 3 pings M 1 ping T 1 ping W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 1 ping S 1 ping S 0 pings M 0 pings T 0 pings W
No pings yet today
No pings yesterday
Scrapy 13 Amazonbot 9 Perplexity 7 Google 5 Ahrefs 4 Unknown AI 2 Claude 2 ChatGPT 2 Meta AI 1 PetalBot 1
crawler 40 crawler_json 6
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Use STDIN/STDOUT/STDERR for IO, always return proper exit codes (0 success, non-zero error), explicitly set memory_limit and time limits for long-running scripts, and handle SIGTERM/SIGINT with pcntl_signal() to allow graceful shutdown
📦 Applies To
PHP 5.0+ cli queue-worker laravel symfony
🔗 Prerequisites
🔍 Detection Hints
CLI script without SIGTERM handler; memory_limit not managed for long-running tasks; missing exit codes
Auto-detectable: ✗ No phpstan symfony-console
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: Medium ✗ Manual fix Fix: Medium Context: File


✓ schema.org compliant