/** * @return \Carrooi\Tokenizer\Matching\Matcher */ public function classDeclaration() { $typeMatcher = new Matcher(); $typeMatcher->select($typeMatcher->expr()->anyOf(Lexer::T_FINAL, Lexer::T_ABSTRACT), Lexer::T_WHITESPACE); $extendsMatcher = new Matcher(); $extendsMatcher->select(Lexer::T_WHITESPACE, Lexer::T_EXTENDS, Lexer::T_WHITESPACE, $this->className()); $implementsDelimiterMatcher = new Matcher(); $implementsDelimiterMatcher->select($implementsDelimiterMatcher->expr()->notRequired(Lexer::T_WHITESPACE), Lexer::T_COMMA, $implementsDelimiterMatcher->expr()->notRequired(Lexer::T_WHITESPACE)); $implementsMatcher = new Matcher(); $implementsMatcher->select(Lexer::T_WHITESPACE, Lexer::T_IMPLEMENTS, Lexer::T_WHITESPACE, $implementsMatcher->expr()->listOf($implementsDelimiterMatcher, $this->className())); $matcher = new Matcher(); $matcher->select($matcher->expr()->notRequired($typeMatcher), Lexer::T_CLASS, Lexer::T_WHITESPACE, Lexer::T_STRING, $matcher->expr()->notRequired($extendsMatcher), $matcher->expr()->notRequired($implementsMatcher)); $matcher->map(new ResultMapping(function (array $tokens) { $class = new ClassDeclaration(Helpers::flattenTokens($tokens), $tokens[3]['value']); if ($tokens[0]) { if ($tokens[0][0]['type'] === Lexer::T_FINAL) { $class->final = true; } if ($tokens[0][0]['type'] === Lexer::T_ABSTRACT) { $class->abstract = true; } } if ($tokens[4] && $tokens[4][3]) { $class->extends = $tokens[4][3]; } if ($tokens[5]) { $implements = array_slice($tokens[5], 3); $implements = array_filter($implements, function ($token) { return $token instanceof ClassNameExpression; }); $class->implements = array_values($implements); } return $class; })); return $matcher; }