Skip to content

Language: static::/self::/parent:: method call in function compiles — Zend Cannot use "static" when no class scope is active (Zend/zend_compile.c) #32227

Description

@PurHur

Category

language · php-src-strict · compile-time fatal · self/parent/static (not #29096)

Problem

A function (no class scope) that contains static::foo(), self::foo(), or parent::foo() compiles and runs to accepted if the function is never called. Zend is a compile-time fatal even when f() is unused:

Cannot use "static" when no class scope is active (same for self / parent).

If f() is invoked, VM/JIT then throw a runtime Error (Cannot access "static" when no class scope is active). Zend never reaches runtime — the file does not compile. That is a silent-accept of an illegal program (rc=0 vs 255).

#29096 (closed) was eval at top level: runtime message wording (Cannot use … in the global scope vs Zend Cannot access …). Distinct: here the method-call form is not rejected at compile at all. static::class / self::class in a function already compile-abort on VM (wording still #29096-shaped).

Verified 2026-08-18 @ 3633ba3bb9 vs Zend 8.2.32.

Repro Zend 8.2.32 VM / JIT
function f() { static::foo(); } echo "accepted"; Fatal Cannot use "static" when no class scope is active accepted (rc=0)
function f() { self::foo(); } echo "accepted"; Fatal Cannot use "self" when no class scope is active accepted (rc=0)
function f() { parent::foo(); } echo "accepted"; Fatal Cannot use "parent" when no class scope is active accepted (rc=0)
function f() { echo static::class; } (control) same Zend fatal VM already compile-aborts (message: global scope)

php-src reference

  • php/php-src Zend/zend_compile.czend_compile_class_ref() / ZEND_FETCH_CLASS_SELF|PARENT|STATIC with !CG(active_class_entry)Cannot use "%s" when no class scope is active

PHP implementation target

Repro

./script/docker-exec.sh -- bash -lc 'php bin/vm.php test/repro/maintainer_gap_static_call_no_scope.php 2>&1 | head -5'
./script/docker-exec.sh -- bash -lc 'php bin/vm.php test/repro/maintainer_gap_self_call_no_scope.php 2>&1 | head -5'
./script/docker-exec.sh -- bash -lc 'php bin/vm.php test/repro/maintainer_gap_parent_call_no_scope.php 2>&1 | head -5'
./script/docker-exec.sh -- bash -lc 'php bin/jit.php test/repro/maintainer_gap_static_call_no_scope.php 2>&1 | head -5'
<?php
function f(): void {
    static::foo();
}
echo "accepted\n";

Done when

  • VM and JIT compile-abort with Zend substring Cannot use "static" when no class scope is active (never print accepted); same for self and parent method-call forms
  • Invoking f() is unnecessary — fatal is at compile, matching Zend
  • static::class / self::class in a function still compile-abort (prefer Zend “no class scope is active” wording)
  • Compliance .phpt guard under test/compliance/cases/language/
  • php-src-strict; no php-compiler-strict shortcut

Activity

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 machinebugSomething isn't workingimplementation-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