Skip to content

Language: first-class callable (strlen(...), Foo::bar(...)) must yield Closure objects (zend_compile.c) #4810

Description

@PurHur

Category

language

Problem

PHP 8.1+ first-class callables must be Closure instances (or invokable objects with __invoke), not compile-time string/[class, method] placeholders. This build lowers strlen(...), array_slice(...), and Foo::bar(...) to strings or array pairs, so is_object($f) is false and var_export() shows 'strlen' instead of a Closure::__set_state array.

Related closed tracker #1230 (parse/lowering landed) but runtime zval type still diverges from Zend.

php-src reference

Repro

test/tmp/repro-fcc-closure-object.php:

<?php
declare(strict_types=1);
$f = strlen(...);
var_export(is_object($f));
echo PHP_EOL;
var_export($f instanceof Closure);
echo PHP_EOL;
./script/docker-exec.sh -- bash -lc 'php test/tmp/repro-fcc-closure-object.php; php bin/vm.php test/tmp/repro-fcc-closure-object.php'
Check Zend This compiler
is_object($f) true false
$f instanceof Closure true false

Also: array_slice(...) — Zend true, VM false (same lowering).

Scope

Module Path
Compiler lib/Compiler.php — compileFirstClassCallable()
VM Closure / callable object construction
Tests test/compliance/cases/language/ + JIT when execute probe green

Done when

  • strlen(...), static Foo::bar(...), and instance [$o, 'm'](...) FCC forms are Closure (or Zend-equivalent invokable)
  • is_callable($fcc) / call_user_func($fcc, ...) parity with Zend on the repro
  • ./script/ci-fast.sh --filter first_class (or new compliance case name) green

Related

Activity

  1. added
    enhancementNew feature or request
    area:vmVirtual machine
    implementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claim
    on Jun 3, 2026
  2. PurHur commented on Jun 3, 2026

    @PurHur
    OwnerAuthor

    claim: cursor-agent-lane-b — starting this run

  3. PurHur commented on Jun 3, 2026

    @PurHur
    OwnerAuthor

    Merged via #4961

    Verification
    ```bash
    ./script/docker-exec.sh -- bash -lc 'php test/tmp/repro-fcc-closure-object.php; php bin/vm.php test/tmp/repro-fcc-closure-object.php'

    true / true (Zend) → true / true (VM)

    vendor/bin/phpunit --filter first_class_callable_closure_object # OK (2 tests)
    ```

    Function/static FCC are Closure objects on VM+JIT; instance-method FCC still blocked at compile by TypeReconstructor::array() (tracked separately).

  4. PurHur commented on Jul 30, 2026

    @PurHur
    OwnerAuthor

    Cleanup: deleting leftover test/tmp/ scratch repro for this closed issue — same coverage lives under test/compliance/cases/ (see PR chore/cleanup-stale-test-tmp-repros).

  5. PurHur commented on Jul 30, 2026

    @PurHur
    OwnerAuthor

    Cleanup follow-up: merged #25413 — test/tmp scratch repro removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:compilerCompiler / CFG / JITarea:vmVirtual machineenhancementNew feature or requestimplementation-readySpec complete: repro, php-src ref, done-when — safe for workers to claimphase-2:languagePhase 2 – language features

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions