Fatal error during autoloading of complex inheritance chain with LSP checks since PHP 8.1.0
Open
Nobody has claimed this yet.
Bug
Category: Engine
Status: Verified
- Dominant language
- C
- Stars
- 40.4k
- Forks
- 8.2k
- Avg merge
- 2d 13h
- Merged PRs (30d)
- 96
Description
Description
The following code:
<?php
$depth = 0;
spl_autoload_register(function ($class) use (&$depth) {
$depth++;
$indent = str_repeat('| ', $depth);
echo $indent."$depth: $class\n";
if ($class == 'IFace') {
interface IFace {}
} elseif ($class == 'IFaceImplementor') {
class IFaceImplementor implements IFace {}
} elseif ($class == 'InterfaceOfMainParent') {
interface InterfaceOfMainParent
{
public function methodForSecondaryLspCheck(): IFace;
}
} elseif ($class == 'MainParent') {
abstract class MainParent implements InterfaceOfMainParent
{
public function methodForSecondaryLspCheck(): IFaceImplementor {}
}
} elseif ($class == 'Intermediate') {
abstract class Intermediate extends MainParent {}
} elseif ($class == 'Child1') {
class Child1 extends Intermediate {}
} elseif ($class == 'Child2') {
class Child2 extends Intermediate {}
} elseif ($class == 'EntrypointParent') {
abstract class EntrypointParent
{
abstract public function methodForLspCheck1(): MainParent;
abstract public function methodForLspCheck2(): MainParent;
}
} elseif ($class == 'Entrypoint') {
class Entrypoint extends EntrypointParent
{
public function methodForLspCheck1(): Child1 {}
public function methodForLspCheck2(): Child2 {}
}
}
$depth--;
});
class_exists(Entrypoint::class);
Resulted in this output:
| 1: Entrypoint
| | 2: EntrypointParent
| | 2: Child1
| | | 3: Intermediate
| | | | 4: MainParent
| | | | | 5: InterfaceOfMainParent
| | | | | 5: Child2
Fatal error: During inheritance of MainParent, while autoloading Child2: Uncaught Error: Class "Intermediate" not found in php-wasm run script:29
Stack trace:
#0 php-wasm run script(20): {closure}('Child2')
#1 php-wasm run script(25): {closure}('MainParent')
#2 php-wasm run script(27): {closure}('Intermediate')
#3 php-wasm run script(37): {closure}('Child1')
#4 [internal function]: {closure}('Entrypoint')
#5 php-wasm run script(47): class_exists('Entrypoint')
#6 {main} in php-wasm run script on line 20
But I expected this output instead:
| 1: Entrypoint
| | 2: EntrypointParent
| | 2: Child1
| | | 3: Intermediate
| | | | 4: MainParent
| | | | | 5: InterfaceOfMainParent
| | | | | 5: IFaceImplementor
| | | | | | 6: IFace
| | 2: Child2
- Full reproduction repository: https://github.com/janedbal/php-bug-complex-inheritance-chain-autoloading
- 3v4l version: https://3v4l.org/G5fFe
- Broken since: PHP 8.1.0
PHP Version
PHP 8.5.0RC1 (cli) (built: Oct 8 2025 22:41:41) (NTS)
Copyright (c) The PHP Group
Built by https://github.com/docker-library/php
Zend Engine v4.5.0RC1, Copyright (c) Zend Technologies
with Zend OPcache v8.5.0RC1, Copyright (c), by Zend Technologies
Operating System
No response
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the reproduction repository and the class_exists(Entrypoint::class) entry point, then compare the autoload trace on PHP 8.1.0 and newer versions. Investigate the inheritance and LSP-check sequence shown in the issue. Done means the reproduction completes without the fatal error and produces the expected autoload order.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100