{
    "slug": "type_declarations",
    "term": "Type Declarations Overview",
    "category": "php",
    "difficulty": "intermediate",
    "short": "PHP's full type system: scalar types, return types, union types, intersection types, nullable, never, and mixed — all enforced at runtime.",
    "long": "PHP's type system has grown substantially: PHP 7.0 added scalar type hints (int, float, string, bool) and return types; 7.1 added nullable (?Type) and void; 7.4 added typed properties; 8.0 added union types (A|B), mixed, static return type, and the never placeholder; 8.1 added intersection types (A&B), never return type, and readonly properties; 8.2 added standalone null, false, true types. Combine with declare(strict_types=1) for strict runtime enforcement. Static analysers (PHPStan, Psalm) use these to verify type correctness without execution.",
    "aliases": [
        "PHP type hints",
        "PHP return types",
        "typed properties"
    ],
    "tags": [
        "php7",
        "php8",
        "php",
        "type-system"
    ],
    "misconception": "Type declarations in PHP are just documentation hints. In PHP 7+ they are enforced at runtime — passing the wrong type throws a TypeError. With strict_types=1 they become strict; without it PHP coerces compatible types. Typed properties (PHP 7.4+) additionally prevent uninitialized access.",
    "why_it_matters": "Type declarations turn runtime surprises into parse-time or call-time errors — a function that declares int $id cannot silently receive a user-supplied string. They are the lowest-effort, highest-return safety net in PHP.",
    "common_mistakes": [
        "Not enabling strict_types=1 — without it PHP coerces types silently, defeating much of the safety benefit.",
        "Using mixed or no type at all \"just in case\" — be as specific as possible, loosen only when truly needed.",
        "Declaring nullable types (?string) out of habit when null is never a valid input.",
        "Forgetting return type declarations — parameter types alone leave the output unguarded."
    ],
    "when_to_use": [
        "Declare parameter and return types on all public methods — they serve as enforced documentation.",
        "Use declare(strict_types=1) at the top of every PHP file to prevent silent type coercion."
    ],
    "avoid_when": [
        "Avoid mixed as a type declaration — it disables type checking entirely and signals unclear design.",
        "Do not use type declarations as a substitute for input validation on data coming from outside PHP."
    ],
    "related": [
        "strict_types",
        "union_types",
        "intersection_types",
        "nullable_types",
        "never_return_type"
    ],
    "prerequisites": [
        "strict_types",
        "nullable_types",
        "union_types"
    ],
    "refs": [
        "https://www.php.net/manual/en/language.types.declarations.php"
    ],
    "bad_code": "// No type declarations — bugs hide until runtime:\nfunction applyDiscount($price, $percent) {\n    return $price - ($price * $percent / 100);\n}\napplyDiscount('ten dollars', '20%'); // No error — returns 0\n\n// With type declarations:\nfunction applyDiscount(float $price, float $percent): float {\n    return $price - ($price * $percent / 100);\n}\napplyDiscount('ten dollars', '20%'); // TypeError immediately",
    "good_code": "<?php declare(strict_types=1);\n\nclass UserService {\n    // Typed property (PHP 7.4)\n    private array $cache = [];\n\n    // Parameter + return types\n    public function findById(int $id): ?User { return null; }\n\n    // Union type (PHP 8.0)\n    public function findByIdOrEmail(int|string $identifier): ?User { return null; }\n\n    // Intersection type (PHP 8.1) — must be Countable AND Iterator\n    public function processAll(\\Countable&\\Iterator $items): void {}\n\n    // never return type (PHP 8.1)\n    public function fail(string $msg): never {\n        throw new \\RuntimeException($msg);\n    }\n\n    // Enum param (PHP 8.1)\n    public function filterByStatus(OrderStatus $status): array { return []; }\n}",
    "quick_fix": "Add declare(strict_types=1) at the top of every file and add parameter/return types to every function signature",
    "severity": "medium",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-03-31",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/type_declarations",
        "html_url": "https://codeclaritylab.com/glossary/type_declarations",
        "json_url": "https://codeclaritylab.com/glossary/type_declarations.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": "[Type Declarations Overview](https://codeclaritylab.com/glossary/type_declarations) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/type_declarations"
            }
        }
    }
}