{
    "slug": "php_cli",
    "term": "PHP CLI & Command-Line Scripts",
    "category": "php",
    "difficulty": "beginner",
    "short": "Running PHP from the command line for scripts, queue workers, cron jobs, and interactive tools — a distinct execution context from web requests.",
    "long": "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.",
    "aliases": [
        "PHP command line",
        "php cli",
        "CLI scripts"
    ],
    "tags": [
        "php",
        "cli",
        "devops",
        "tooling"
    ],
    "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."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "async_processing",
        "php_fpm",
        "generators",
        "memory_leak"
    ],
    "prerequisites": [
        "php_error_levels",
        "generators",
        "php_concurrency_options"
    ],
    "refs": [
        "https://www.php.net/manual/en/features.commandline.php",
        "https://symfony.com/doc/current/components/console.html"
    ],
    "bad_code": "// CLI script with no exit code handling — CI can't detect failure:\n<?php\ntry {\n    runImport();\n} catch (Exception $e) {\n    echo $e->getMessage(); // Prints error but exits with 0 — CI thinks success\n}\n// Fix: exit(1) on failure",
    "good_code": "#!/usr/bin/env php\n<?php\n// Guard: must not run via web\nif (php_sapi_name() !== 'cli') {\n    fwrite(STDERR, \"CLI only.\\n\"); exit(1);\n}\n\n// Parse arguments\n\\$opts   = getopt('u:v', ['user:', 'verbose']);\n\\$userId = \\$opts['u'] ?? \\$opts['user'] ?? null;\n\\$verbose = isset(\\$opts['v']) || isset(\\$opts['verbose']);\n\nif (!\\$userId) {\n    fwrite(STDERR, \"Usage: php script.php -u <user_id>\\n\"); exit(1);\n}\n\nfwrite(STDOUT, \"Processing user \\$userId\\n\");\n\n// Exit codes: 0 = success, non-zero = error\nexit(0);",
    "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",
    "severity": "medium",
    "effort": "low",
    "created": "2026-03-15",
    "updated": "2026-04-16",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/php_cli",
        "html_url": "https://codeclaritylab.com/glossary/php_cli",
        "json_url": "https://codeclaritylab.com/glossary/php_cli.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[PHP CLI & Command-Line Scripts](https://codeclaritylab.com/glossary/php_cli) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/php_cli"
            }
        }
    }
}