{
    "slug": "static_methods",
    "term": "Static Methods & Properties",
    "category": "php",
    "difficulty": "intermediate",
    "short": "Class-level methods and properties that exist independently of any instance — useful for utilities and factories, but harmful when overused.",
    "long": "Static methods and properties belong to the class rather than an instance and are called with :: (ClassName::method()). They are appropriate for: pure utility functions (Math::clamp()), named constructors/factories (Money::fromFloat()), and singleton registries. However, static state is global state — it persists across test cases, cannot be easily mocked, and creates hidden dependencies. Static calls are hard to stub in tests without workarounds like Mockery's alias mocking. Prefer instance methods with dependency injection for anything stateful or replaceable; reserve static for genuinely stateless utilities.",
    "aliases": [
        "PHP static",
        "static method",
        "static property"
    ],
    "tags": [
        "php",
        "oop",
        "testing",
        "coupling"
    ],
    "misconception": "Static methods are just regular methods that do not need instantiation. Static methods are globally accessible shared state — they cannot be mocked by standard test doubles, create hidden dependencies, and make code harder to reason about in concurrent contexts.",
    "why_it_matters": "Static methods couple callers to a specific class and cannot be easily mocked or swapped — overusing them creates hidden global dependencies that resist unit testing.",
    "common_mistakes": [
        "Using static methods for stateful operations — global state in static methods causes test pollution.",
        "Static factory methods that return a concrete type — cannot be overridden in subclasses without LSP violation.",
        "Calling static methods on $this inside a class — use self:: or static:: explicitly.",
        "Not distinguishing stateless utility statics (Math::round()) from stateful service statics (DB::query()) — the former is fine, the latter is problematic."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "singleton",
        "late_static_binding",
        "dependency_injection",
        "pure_function"
    ],
    "prerequisites": [
        "late_static_binding",
        "single_responsibility",
        "dependency_injection"
    ],
    "refs": [
        "https://www.php.net/manual/en/language.oop5.static.php"
    ],
    "bad_code": "// Static method with global state — cannot be unit tested:\nclass Database {\n    private static ?PDO $connection = null;\n    public static function query(string $sql): array {\n        return self::getConnection()->query($sql)->fetchAll();\n    }\n}\n// Callers: Database::query() — tightly coupled, untestable without real DB",
    "good_code": "// Static methods: no instance state, utility/factory use cases\nclass Uuid {\n    public static function v4(): string {\n        return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',\n            mt_rand(0, 0xffff), mt_rand(0, 0xffff),\n            mt_rand(0, 0xffff),\n            mt_rand(0, 0x0fff) | 0x4000,\n            mt_rand(0, 0x3fff) | 0x8000,\n            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)\n        );\n    }\n}\n$id = Uuid::v4();\n\n// Named constructors — static factory on a value object\nreadonly class Temperature {\n    private function __construct(public float $celsius) {}\n    public static function fromCelsius(float $c): self    { return new self($c); }\n    public static function fromFahrenheit(float $f): self  { return new self(($f-32)*5/9); }\n    public static function fromKelvin(float $k): self      { return new self($k-273.15); }\n}",
    "quick_fix": "Replace static utility methods with injected service objects — static calls create hidden global dependencies that can't be mocked, swapped, or configured per-context",
    "severity": "medium",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/static_methods",
        "html_url": "https://codeclaritylab.com/glossary/static_methods",
        "json_url": "https://codeclaritylab.com/glossary/static_methods.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": "[Static Methods & Properties](https://codeclaritylab.com/glossary/static_methods) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/static_methods"
            }
        }
    }
}