{
    "slug": "first_class_callables",
    "term": "First Class Callable Syntax (PHP 8.1)",
    "category": "php",
    "difficulty": "intermediate",
    "short": "Creates a Closure from any callable using func(...) syntax, replacing the verbose Closure::fromCallable() boilerplate.",
    "long": "PHP 8.1 introduced the first class callable syntax: $fn = strlen(...) creates a Closure bound to strlen. This works with functions, static methods, instance methods, and built-in functions. It replaces the verbose Closure::fromCallable('strlen') pattern and avoids string-based callables which are not type-safe and don't survive renaming refactors. First class callables compose well with array_map(), usort(), and other higher-order functions.",
    "aliases": [
        "first-class callable syntax",
        "PHP 8.1 callables",
        "... callable shorthand"
    ],
    "tags": [
        "php8",
        "php",
        "functional",
        "syntax"
    ],
    "misconception": "First-class callables and Closure::fromCallable() behave differently at runtime. They produce identical Closure objects — the difference is purely syntactic. strlen(...) is cleaner and works consistently for methods, static methods, and built-in functions.",
    "why_it_matters": "PHP 8.1 first-class callable syntax (strlen(...)) creates a Closure from any callable — eliminating the fragile string-based Closure::fromCallable('strlen') pattern and making refactoring tools able to track references.",
    "common_mistakes": [
        "Still using Closure::fromCallable('method') when the first-class callable syntax is available and cleaner.",
        "Using string callables ('strlen') where a first-class callable would allow IDE to verify the function exists.",
        "Not realising that the syntax works for static methods (Foo::bar(...)), instance methods ($obj->method(...)), and built-ins.",
        "Using it where a simple anonymous function is clearer — fn($x) => transform($x) vs transform(...)."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "closures",
        "arrow_functions"
    ],
    "prerequisites": [
        "closures",
        "arrow_functions",
        "php_data_types"
    ],
    "refs": [
        "https://www.php.net/manual/en/functions.first_class_callable_syntax.php"
    ],
    "bad_code": "// String callable — no IDE support, no refactoring safety:\n$fn = Closure::fromCallable('array_reverse');\n$lengths = array_map('strlen', $strings); // Refactor 'strlen'? IDE won't catch\n\n// First-class callable:\n$fn = array_reverse(...);\n$lengths = array_map(strlen(...), $strings);",
    "good_code": "// PHP 8.1 first-class callable syntax — wrap any callable as a Closure\n// Before: cumbersome\n$fn = Closure::fromCallable('strlen');\n$fn = fn($s) => strlen($s);\n\n// After: clean and composable\n$fn = strlen(...);\n\n// Works on static methods, instance methods, built-ins\n$sort    = usort(...);\n$trim    = trim(...);\n$getAge  = $user->getAge(...);\n$create  = User::create(...);\n\n// Compose with array functions — no more fn($x) => wrapper\n$lengths  = array_map(strlen(...), $strings);\n$sorted   = usort($items, strcmp(...));\n\n// Pass as argument\nfunction transform(array $items, callable $fn): array {\n    return array_map($fn, $items);\n}\n$upper = transform($words, strtoupper(...));",
    "quick_fix": "Replace 'strlen' string callables and Closure::fromCallable() with the cleaner strlen(...) syntax everywhere — PHPStan can analyse the type signature, IDEs can rename, and it's refactoring-safe",
    "severity": "low",
    "effort": "low",
    "created": "2026-03-15",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/first_class_callables",
        "html_url": "https://codeclaritylab.com/glossary/first_class_callables",
        "json_url": "https://codeclaritylab.com/glossary/first_class_callables.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": "[First Class Callable Syntax (PHP 8.1)](https://codeclaritylab.com/glossary/first_class_callables) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/first_class_callables"
            }
        }
    }
}