Skip to content

PHP 8.6: cached static closure keeps static:: of the first called class #23911

Description

@SanderMuller

Description

The following code:

<?php
class A {
    public static function name(): string {
        return (static fn () => static::class)();
    }
}
class B extends A {}
class C extends A {}

var_dump(B::name(), C::name());

Resulted in this output:

string(1) "B"
string(1) "B"

But I expected this output instead:

string(1) "B"
string(1) "C"

8.4 and 8.5 give the expected output. 8.6.0RC2 does not, with or without opcache.

Bisected to f47cd21 (#23203). Its parent 969a50d gives "B", "C". Still reproduces on PHP-8.6 7f56584 and master 69ca307.

Cc @iluuu1994

Written with LLM assistance, per CONTRIBUTING.md. The code, outputs and bisect above are measured.

It also happens in inherited instance methods, and with new static() and get_called_class(). A non-static closure is fine. We hit it in bensampo/laravel-enum, where the second enum class gets instances of the first.

Unverified guess: ZEND_DECLARE_LAMBDA_FUNCTION returns the cached closure without checking the called scope, and all subclasses share the slot in the declaring op_array.

PHP Version

PHP 8.6.0RC2 (cli) (built: Sep 24 2026 20:13:06) (NTS clang 15.0.0)
Copyright © The PHP Group and Contributors
Built by Laravel Herd
Zend Engine v4.6.0RC2, Copyright © Zend by Perforce
    with Zend OPcache v8.6.0RC2, Copyright ©, by Zend by Perforce

Operating System

macOS 26.6.2 (arm64)

Activity

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions