@@ -3825,6 +3825,39 @@ private function isInterfaceMemberDeclarationStart(Token $token) {
38253825 case TokenKind::UseKeyword:
38263826
38273827 case TokenKind::AttributeToken:
3828+
3829+ // PHP 8.4: interface property hooks without explicit visibility
3830+ case TokenKind::QuestionToken: // nullable type: ?Foo $bar
3831+ case TokenKind::VariableName: // no type: $bar
3832+
3833+ // Type tokens that can start a property declaration
3834+ case TokenKind::Name: // qualified names: Foo $bar
3835+ case TokenKind::BackslashToken: // fully qualified: \Foo $bar
3836+ case TokenKind::NamespaceKeyword: // relative: namespace\Foo $bar
3837+ case TokenKind::OpenParenToken: // DNF types: (A&B)|C $bar
3838+
3839+ // Built-in type keywords
3840+ case TokenKind::ArrayKeyword:
3841+ case TokenKind::CallableKeyword:
3842+ case TokenKind::BoolReservedWord:
3843+ case TokenKind::FloatReservedWord:
3844+ case TokenKind::IntReservedWord:
3845+ case TokenKind::StringReservedWord:
3846+ case TokenKind::ObjectReservedWord:
3847+ case TokenKind::NullReservedWord:
3848+ case TokenKind::FalseReservedWord:
3849+ case TokenKind::TrueReservedWord:
3850+ case TokenKind::IterableReservedWord:
3851+ case TokenKind::MixedReservedWord:
3852+ case TokenKind::VoidReservedWord:
3853+ case TokenKind::NeverReservedWord:
3854+
3855+ // Legacy type aliases (for error recovery)
3856+ case TokenKind::BooleanReservedWord:
3857+ case TokenKind::IntegerReservedWord:
3858+ case TokenKind::DoubleReservedWord:
3859+ case TokenKind::RealReservedWord:
3860+ case TokenKind::BinaryReservedWord:
38283861 return true ;
38293862 }
38303863 return false ;
0 commit comments