Example #1
0
 /**
  * Shared implementation for parseFile() & parseContents().
  *
  * @param array $tokens The result of a token_get_all()
  * @param Context $parseContext
  * @return Analysis
  */
 protected function fromTokens($tokens, $parseContext)
 {
     $analyser = new Analyser();
     $analysis = new Analysis();
     reset($tokens);
     $token = '';
     $imports = ['swg' => 'Swagger\\Annotations'];
     // Use @SWG\* for swagger annotations (unless overwritten by a use statement)
     $parseContext->uses = [];
     $classContext = $parseContext;
     // Use the parseContext until a classContext is created.
     $classDefinition = false;
     $comment = false;
     $line = 0;
     $lineOffset = $parseContext->line ?: 0;
     while ($token !== false) {
         $previousToken = $token;
         $token = $this->nextToken($tokens, $parseContext);
         if (is_array($token) === false) {
             // Ignore tokens like "{", "}", etc
             continue;
         }
         if ($token[0] === T_DOC_COMMENT) {
             if ($comment) {
                 // 2 Doc-comments in succession?
                 $analysis->addAnnotations($analyser->fromComment($comment, new Context(['line' => $line], $classContext)));
             }
             $comment = $token[1];
             $line = $token[2] + $lineOffset;
             continue;
         }
         if ($token[0] === T_ABSTRACT) {
             $token = $this->nextToken($tokens, $parseContext);
             // Skip "abstract" keyword
         }
         if ($token[0] === T_CLASS) {
             // Doc-comment before a class?
             if (is_array($previousToken) && $previousToken[0] === T_DOUBLE_COLON) {
                 //php 5.5 class name resolution (i.e. ClassName::class)
                 continue;
             }
             $token = $this->nextToken($tokens, $parseContext);
             $classContext = new Context(['class' => $token[1], 'line' => $token[2]], $parseContext);
             if ($classDefinition) {
                 $analysis->addClassDefinition($classDefinition);
             }
             $classDefinition = ['class' => $token[1], 'extends' => null, 'properties' => [], 'methods' => [], 'context' => $classContext];
             // @todo detect end-of-class and reset $classContext
             $token = $this->nextToken($tokens, $parseContext);
             if ($token[0] === T_EXTENDS) {
                 $classContext->extends = $this->parseNamespace($tokens, $token, $parseContext);
                 $classDefinition['extends'] = $classContext->fullyQualifiedName($classContext->extends);
             }
             if ($comment) {
                 $classContext->line = $line;
                 $analysis->addAnnotations($analyser->fromComment($comment, $classContext));
                 $comment = false;
                 continue;
             }
         }
         if ($token[0] == T_STATIC) {
             $token = $this->nextToken($tokens, $parseContext);
             if ($token[0] === T_VARIABLE) {
                 // static property
                 $propertyContext = new Context(['property' => substr($token[1], 1), 'static' => true, 'line' => $line], $classContext);
                 if ($classDefinition) {
                     $classDefinition['properties'][$propertyContext->property] = $propertyContext;
                 }
                 if ($comment) {
                     $analysis->addAnnotations($analyser->fromComment($comment, $propertyContext));
                     $comment = false;
                 }
                 continue;
             }
         }
         if (in_array($token[0], [T_PRIVATE, T_PROTECTED, T_PUBLIC, T_VAR])) {
             // Scope
             $token = $this->nextToken($tokens, $parseContext);
             if ($token[0] == T_STATIC) {
                 $token = $this->nextToken($tokens, $parseContext);
             }
             if ($token[0] === T_VARIABLE) {
                 // instance property
                 $propertyContext = new Context(['property' => substr($token[1], 1), 'line' => $line], $classContext);
                 if ($classDefinition) {
                     $classDefinition['properties'][$propertyContext->property] = $propertyContext;
                 }
                 if ($comment) {
                     $analysis->addAnnotations($analyser->fromComment($comment, $propertyContext));
                     $comment = false;
                 }
             } elseif ($token[0] === T_FUNCTION) {
                 $token = $this->nextToken($tokens, $parseContext);
                 if ($token[0] === T_STRING) {
                     $methodContext = new Context(['method' => $token[1], 'line' => $line], $classContext);
                     if ($classDefinition) {
                         $classDefinition['methods'][$token[1]] = $methodContext;
                     }
                     if ($comment) {
                         $analysis->addAnnotations($analyser->fromComment($comment, $methodContext));
                         $comment = false;
                     }
                 }
             }
             continue;
         } elseif ($token[0] === T_FUNCTION) {
             $token = $this->nextToken($tokens, $parseContext);
             if ($token[0] === T_STRING) {
                 $methodContext = new Context(['method' => $token[1], 'line' => $line], $classContext);
                 if ($classDefinition) {
                     $classDefinition['methods'][$token[1]] = $methodContext;
                 }
                 if ($comment) {
                     $analysis->addAnnotations($analyser->fromComment($comment, $methodContext));
                     $comment = false;
                 }
             }
         }
         if (in_array($token[0], [T_NAMESPACE, T_USE]) === false) {
             // Skip "use" & "namespace" to prevent "never imported" warnings)
             // Not a doc-comment for a class, property or method?
             if ($comment) {
                 $analysis->addAnnotations($analyser->fromComment($comment, new Context(['line' => $line], $classContext)));
                 $comment = false;
             }
         }
         if ($token[0] === T_NAMESPACE) {
             $parseContext->namespace = $this->parseNamespace($tokens, $token, $parseContext);
             continue;
         }
         if ($token[0] === T_USE) {
             $statements = $this->parseUseStatement($tokens, $token, $parseContext);
             foreach ($statements as $alias => $target) {
                 if ($target[0] === '\\') {
                     $target = substr($target, 1);
                 }
                 $parseContext->uses[$alias] = $target;
                 foreach (Analyser::$whitelist as $namespace) {
                     if (strcasecmp(substr($target, 0, strlen($namespace)), $namespace) === 0) {
                         $imports[strtolower($alias)] = $target;
                         break;
                     }
                 }
             }
             $analyser->docParser->setImports($imports);
             continue;
         }
     }
     if ($comment) {
         // File ends with a T_DOC_COMMENT
         $analysis->addAnnotations($analyser->fromComment($comment, new Context(['line' => $line], $classContext)));
     }
     if ($classDefinition) {
         $analysis->addClassDefinition($classDefinition);
     }
     return $analysis;
 }