class StaticReflectionParser

Same name in this branch
  1. 9 core/modules/migrate/src/Plugin/Discovery/StaticReflectionParser.php \Drupal\migrate\Plugin\Discovery\StaticReflectionParser
Same name and namespace in other branches
  1. 8.9.x core/modules/migrate/src/Plugin/Discovery/StaticReflectionParser.php \Drupal\migrate\Plugin\Discovery\StaticReflectionParser
  2. 10 core/modules/migrate/src/Plugin/Discovery/StaticReflectionParser.php \Drupal\migrate\Plugin\Discovery\StaticReflectionParser
  3. 10 core/lib/Drupal/Component/Annotation/Doctrine/StaticReflectionParser.php \Drupal\Component\Annotation\Doctrine\StaticReflectionParser
  4. 11.x core/modules/migrate/src/Plugin/Discovery/StaticReflectionParser.php \Drupal\migrate\Plugin\Discovery\StaticReflectionParser
  5. 11.x core/lib/Drupal/Component/Annotation/Doctrine/StaticReflectionParser.php \Drupal\Component\Annotation\Doctrine\StaticReflectionParser

Parses a file for namespaces/use/class declarations.

Hierarchy

Expanded class hierarchy of StaticReflectionParser

4 files declare their use of StaticReflectionParser
AnnotatedClassDiscovery.php in core/lib/Drupal/Component/Annotation/Plugin/Discovery/AnnotatedClassDiscovery.php
AnnotatedClassDiscoveryAutomatedProviders.php in core/modules/migrate/src/Plugin/Discovery/AnnotatedClassDiscoveryAutomatedProviders.php
StaticReflectionParser.php in core/modules/migrate/src/Plugin/Discovery/StaticReflectionParser.php
TestDiscovery.php in core/lib/Drupal/Core/Test/TestDiscovery.php

File

core/lib/Drupal/Component/Annotation/Doctrine/StaticReflectionParser.php, line 59

Namespace

Drupal\Component\Annotation\Doctrine
View source
class StaticReflectionParser {
    
    /**
     * The fully qualified class name.
     *
     * @var string
     */
    protected $className;
    
    /**
     * The short class name.
     *
     * @var string
     */
    protected $shortClassName;
    
    /**
     * Whether the caller only wants class annotations.
     *
     * @var bool
     */
    protected $classAnnotationOptimize;
    
    /**
     * A ClassFinder object which finds the class.
     *
     * @var ClassFinderInterface
     */
    protected $finder;
    
    /**
     * Whether the parser has run.
     *
     * @var bool
     */
    protected $parsed = false;
    
    /**
     * The namespace of the class.
     *
     * @var string
     */
    protected $namespace = '';
    
    /**
     * The use statements of the class.
     *
     * @var string[]
     */
    protected $useStatements = [];
    
    /**
     * The docComment of the class.
     *
     * @var mixed[]
     */
    protected $docComment = [
        'class' => '',
        'property' => [],
        'method' => [],
    ];
    
    /**
     * The name of the class this class extends, if any.
     *
     * @var string
     */
    protected $parentClassName = '';
    
    /**
     * The parent PSR-0 Parser.
     *
     * @var \Doctrine\Common\Reflection\StaticReflectionParser
     */
    protected $parentStaticReflectionParser;
    
    /**
     * Parses a class residing in a PSR-0 hierarchy.
     *
     * @param string               $className               The full, namespaced class name.
     * @param ClassFinderInterface $finder                  A ClassFinder object which finds the class.
     * @param bool                 $classAnnotationOptimize Only retrieve the class docComment.
     *                                                         Presumes there is only one statement per line.
     */
    public function __construct($className, $finder, $classAnnotationOptimize = false) {
        $this->className = ltrim($className, '\\');
        $lastNsPos = strrpos($this->className, '\\');
        if ($lastNsPos !== false) {
            $this->namespace = substr($this->className, 0, $lastNsPos);
            $this->shortClassName = substr($this->className, $lastNsPos + 1);
        }
        else {
            $this->shortClassName = $this->className;
        }
        $this->finder = $finder;
        $this->classAnnotationOptimize = $classAnnotationOptimize;
    }
    
    /**
     * @return void
     */
    protected function parse() {
        $fileName = $this->finder
            ->findFile($this->className);
        if ($this->parsed || !$fileName) {
            return;
        }
        $this->parsed = true;
        $contents = file_get_contents($fileName);
        if ($this->classAnnotationOptimize) {
            $regex = sprintf('/\\A.*^\\s*((abstract|final)\\s+)?class\\s+%s\\s+/sm', $this->shortClassName);
            if (preg_match($regex, $contents, $matches)) {
                $contents = $matches[0];
            }
        }
        $tokenParser = new TokenParser($contents);
        $docComment = '';
        $last_token = false;
        while ($token = $tokenParser->next(false)) {
            switch ($token[0]) {
                case T_USE:
                    $this->useStatements = array_merge($this->useStatements, $tokenParser->parseUseStatement());
                    break;
                case T_DOC_COMMENT:
                    $docComment = $token[1];
                    break;
                case T_CLASS:
                    if ($last_token !== T_PAAMAYIM_NEKUDOTAYIM && $last_token !== T_NEW) {
                        $this->docComment['class'] = $docComment;
                        $docComment = '';
                    }
                    break;
                case T_VAR:
                case T_PRIVATE:
                case T_PROTECTED:
                case T_PUBLIC:
                    $token = $tokenParser->next();
                    if ($token[0] === T_VARIABLE) {
                        $propertyName = substr($token[1], 1);
                        $this->docComment['property'][$propertyName] = $docComment;
                        continue 2;
                    }
                    if ($token[0] !== T_FUNCTION) {
                        // For example, it can be T_FINAL.
                        continue 2;
                    }
                // No break.
                case T_FUNCTION:
                    // The next string after function is the name, but
                    // there can be & before the function name so find the
                    // string.
                    while (($token = $tokenParser->next()) && $token[0] !== T_STRING) {
                        continue;
                    }
                    if ($token === null) {
                        break;
                    }
                    $methodName = $token[1];
                    $this->docComment['method'][$methodName] = $docComment;
                    $docComment = '';
                    break;
                case T_EXTENDS:
                    $this->parentClassName = $tokenParser->parseClass();
                    $nsPos = strpos($this->parentClassName, '\\');
                    $fullySpecified = false;
                    if ($nsPos === 0) {
                        $fullySpecified = true;
                    }
                    else {
                        if ($nsPos) {
                            $prefix = strtolower(substr($this->parentClassName, 0, $nsPos));
                            $postfix = substr($this->parentClassName, $nsPos);
                        }
                        else {
                            $prefix = strtolower($this->parentClassName);
                            $postfix = '';
                        }
                        foreach ($this->useStatements as $alias => $use) {
                            if ($alias !== $prefix) {
                                continue;
                            }
                            $this->parentClassName = '\\' . $use . $postfix;
                            $fullySpecified = true;
                        }
                    }
                    if (!$fullySpecified) {
                        $this->parentClassName = '\\' . $this->namespace . '\\' . $this->parentClassName;
                    }
                    break;
            }
            $last_token = is_array($token) ? $token[0] : false;
        }
    }
    
    /**
     * @return StaticReflectionParser
     */
    protected function getParentStaticReflectionParser() {
        if (empty($this->parentStaticReflectionParser)) {
            $this->parentStaticReflectionParser = new static($this->parentClassName, $this->finder);
        }
        return $this->parentStaticReflectionParser;
    }
    
    /**
     * @return string
     */
    public function getClassName() {
        return $this->className;
    }
    
    /**
     * @return string
     */
    public function getNamespaceName() {
        return $this->namespace;
    }
    
    /**
     * Gets the ReflectionClass equivalent for this class.
     *
     * @return ReflectionClass
     */
    public function getReflectionClass() {
        return new StaticReflectionClass($this);
    }
    
    /**
     * Gets the use statements from this file.
     *
     * @return string[]
     */
    public function getUseStatements() {
        $this->parse();
        return $this->useStatements;
    }
    
    /**
     * Gets the doc comment.
     *
     * @param string $type The type: 'class', 'property' or 'method'.
     * @param string $name The name of the property or method, not needed for 'class'.
     *
     * @return string The doc comment, empty string if none.
     */
    public function getDocComment($type = 'class', $name = '') {
        $this->parse();
        return $name ? $this->docComment[$type][$name] : $this->docComment[$type];
    }
    
    /**
     * Gets the PSR-0 parser for the declaring class.
     *
     * @param string $type The type: 'property' or 'method'.
     * @param string $name The name of the property or method.
     *
     * @return StaticReflectionParser A static reflection parser for the declaring class.
     *
     * @throws ReflectionException
     */
    public function getStaticReflectionParserForDeclaringClass($type, $name) {
        $this->parse();
        if (isset($this->docComment[$type][$name])) {
            return $this;
        }
        if (!empty($this->parentClassName)) {
            return $this->getParentStaticReflectionParser()
                ->getStaticReflectionParserForDeclaringClass($type, $name);
        }
        throw new ReflectionException('Invalid ' . $type . ' "' . $name . '"');
    }

}

Members

Title Sort descending Modifiers Object type Summary
StaticReflectionParser::$classAnnotationOptimize protected property Whether the caller only wants class annotations.
StaticReflectionParser::$className protected property The fully qualified class name.
StaticReflectionParser::$docComment protected property The docComment of the class.
StaticReflectionParser::$finder protected property A ClassFinder object which finds the class.
StaticReflectionParser::$namespace protected property The namespace of the class.
StaticReflectionParser::$parentClassName protected property The name of the class this class extends, if any.
StaticReflectionParser::$parentStaticReflectionParser protected property The parent PSR-0 Parser.
StaticReflectionParser::$parsed protected property Whether the parser has run.
StaticReflectionParser::$shortClassName protected property The short class name.
StaticReflectionParser::$useStatements protected property The use statements of the class.
StaticReflectionParser::getClassName public function
StaticReflectionParser::getDocComment public function Gets the doc comment.
StaticReflectionParser::getNamespaceName public function
StaticReflectionParser::getParentStaticReflectionParser protected function
StaticReflectionParser::getReflectionClass public function Gets the ReflectionClass equivalent for this class.
StaticReflectionParser::getStaticReflectionParserForDeclaringClass public function Gets the PSR-0 parser for the declaring class.
StaticReflectionParser::getUseStatements public function Gets the use statements from this file.
StaticReflectionParser::parse protected function
StaticReflectionParser::__construct public function Parses a class residing in a PSR-0 hierarchy.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.