Skip to content

zend_ast: Fix AST export of static member names that do not lex as identifiers - #25330

Closed
jorgsowa wants to merge 1 commit into
php:PHP-8.4from
jorgsowa:fix-ast-export-unlexable-static-member
Closed

jorgsowa wants to merge 1 commit into
php:PHP-8.4from
jorgsowa:fix-ast-export-unlexable-static-member

Conversation

@jorgsowa

@jorgsowa jorgsowa commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

The AST export of static method calls and class constant fetches prints dynamic member names without braces, even when the bare name doesn't lex as an identifier. The exported code then fails to parse:

assert(false && C::{'__halt_compiler'}());
// AssertionError: assert(false && C::__halt_compiler())
// re-parsing it: syntax error, unexpected token "__halt_compiler"

Three cases are affected:

  • __halt_compiler: T_HALT_COMPILER is the only keyword the grammar does not accept as an identifier, so C::{'__halt_compiler'} cannot be written as C::__halt_compiler.
  • Names that aren't valid labels: static call names went through the variable-name export path, so C::{'a b'}() became C::{a b}() and C::{''}() became C::{}().
  • public/protected/private calls: C::public( set ) was exported as C::public(set), which the lexer reads as the single T_PUBLIC_SET token.

These names are now exported in braces: C::{'_halt_compiler'}(), C::{'a b'}(), C::{'public'}(set). A static call named public, protected or private is always braced, because only its arguments decide whether it would lex as T*_SET, and the braced form is always valid.

Follow-up to #25221.

@jorgsowa
jorgsowa requested a review from iliaal November 8, 2026 20:47
@jorgsowa jorgsowa self-assigned this Nov 8, 2026

@iliaal iliaal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

zend_ast_export_var() has the same unquoted-brace problem for the other member kinds: $o->{'a b'}(), $o?->{'a b'}(), $o->{'a b'}, C::${'a b'} and ${'a b'} all still export as {a b}. Exporting the ZVAL with zend_ast_export_ex() inside the braces there would fix all of them, and the static call path would only need the __halt_compiler/public(set) checks.

@jorgsowa

jorgsowa commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor Author

I'm not gonna fix it on 8.4. Whole zend_ast is too buggy on 8.4 to reliable make separate fixes. This problem is partially already fixed on 8.6, so I will create separate branch to address it only for 8.6. Thank you for review

@jorgsowa jorgsowa closed this Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants