예제 #1
0
 /**
  * @inheritdoc
  */
 public function check(\SplFileInfo $file, Tokens $tokens)
 {
     if (in_array(preg_replace('#/+#', '/', $file->getPathname()), $this->excludedFiles, true)) {
         return;
     }
     $namespaces = [];
     $classes = [];
     foreach ($tokens as $index => $token) {
         if ($token->isGivenKind(T_NAMESPACE)) {
             $namespaceIndex = $tokens->getNextNonWhitespace($index);
             $namespaceEndIndex = $tokens->getNextTokenOfKind($index, array(';'));
             $namespaces[$index] = trim($tokens->generatePartialCode($namespaceIndex, $namespaceEndIndex - 1));
         } elseif ($token->isClassy()) {
             $classyIndex = $tokens->getNextNonWhitespace($index);
             $classes[$classyIndex] = $tokens[$classyIndex]->getContent();
         }
     }
     list($namespace, $namespaceIndex) = $this->resolveNamespace($tokens, $namespaces);
     list($className, $classNameIndex) = $this->resolveClassName($tokens, $classes);
     // Check namespace directory
     $this->checkNamespaceDirectory($file, $tokens, $namespace, $namespaceIndex);
     // File basename must match class name
     $fileBasename = $file->getBasename('.' . $file->getExtension());
     if ($className !== null && $fileBasename !== $className) {
         $tokens->reportAt($classNameIndex, new Message(E_ERROR, 'check_psr4_filename_must_match_classname', ['expected' => $fileBasename, 'class' => $className]));
     }
 }
 private function checkMethodSignature(Tokens $tokens, $methodName, $methodFunctionIndex)
 {
     $startParenthesisIndex = $tokens->getNextTokenOfKind($methodFunctionIndex, array('('));
     $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startParenthesisIndex);
     for ($index = $startParenthesisIndex; $index < $endParenthesisIndex; ++$index) {
         if (!$tokens[$index]->isGivenKind(T_VARIABLE)) {
             continue;
         }
         $tokens->reportAt($index, new Message(E_ERROR, 'check_method_arguments_not_allowed', ['method' => $methodName]));
         break;
     }
 }
 /**
  * @inheritdoc
  */
 public function check(\SplFileInfo $file, Tokens $tokens)
 {
     $analyzer = new TokensAnalyzer($tokens);
     $constructorIndex = null;
     $constructorArgs = [];
     $properties = [];
     // Find the class
     $classIndex = $tokens->getNextTokenOfKind(0, [[T_CLASS]]);
     if ($classIndex === null) {
         return;
     }
     $classAttributes = TokensHelper::getClassAttributes($tokens, $classIndex);
     // Event must be final or abstract
     if (!$classAttributes['abstract'] && !$classAttributes['final']) {
         $tokens->reportAt($classIndex, new Message(E_ERROR, 'check_class_must_be_final_or_abstract', ['class' => $classAttributes['name']]));
     }
     $elements = $analyzer->getClassyElements();
     foreach ($elements as $index => $element) {
         /** @var Token $token */
         if ($element['type'] === 'method') {
             $methodAttributes = TokensHelper::getMethodAttributes($tokens, $index, $analyzer);
             if ($methodInfo = $this->checkMethod($tokens, $index, $methodAttributes)) {
                 $constructorIndex = $index;
                 $constructorArgs = $methodInfo['arguments'];
             }
         } elseif ($element['type'] === 'property' && ($propertyInfo = $this->checkProperty($tokens, $index))) {
             $properties[$index] = $propertyInfo;
         }
     }
     // A event without data is not a error
     if ($constructorIndex === null && count($properties) === 0) {
         return;
     }
     // Event with properties must have a constructor
     if ($constructorIndex === null) {
         $tokens->reportAt($classIndex, new Message(E_ERROR, 'check_class_must_have_constructor', ['class' => $classAttributes['name']]));
     } else {
         $expectedProperties = array_map(function ($info) {
             return $info['token']->getContent();
         }, $constructorArgs);
         $unknownConstructorArgs = array_diff($expectedProperties, $properties);
         if (count($unknownConstructorArgs) > 0) {
             $tokens->reportAt($constructorIndex, new Message(E_ERROR, 'check_class_constructor_has_arguments_without_related_property', ['arguments' => implode(', ', $unknownConstructorArgs)]));
         }
         $unassignedProperties = array_diff($properties, $expectedProperties);
         if (count($unassignedProperties) > 0) {
             foreach ($unassignedProperties as $index => $property) {
                 $tokens->reportAt($index, new Message(E_ERROR, 'check_class_property_must_be_know_as_constructor_argument', ['property' => $property]));
             }
         }
     }
 }
예제 #4
0
 /**
  * @inheritdoc
  */
 public function check(\SplFileInfo $file, Tokens $tokens)
 {
     $tokenCount = $tokens->count();
     for ($index = 0; $index < $tokenCount; ++$index) {
         $token = $tokens[$index];
         if (!$token->isGivenKind(T_CLASS)) {
             continue;
         }
         $prevToken = $tokens[$tokens->getPrevMeaningfulToken($index)];
         $classStart = $tokens->getNextTokenOfKind($index, array('{'));
         $classEnd = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $classStart);
         // ignore class if it is abstract or already final
         if ($prevToken->isGivenKind(array(T_ABSTRACT, T_FINAL))) {
             $index = $classEnd;
             continue;
         }
         $classNameIndex = $tokens->getNextTokenOfKind($index, [[T_STRING]]);
         $className = $tokens[$classNameIndex]->getContent();
         $tokens->reportAt($index, new Message(E_ERROR, 'check_class_should_be_final', ['class' => $className]));
         $index = $classEnd;
     }
 }