public function visit(NodeTraversal $t, \PHPParser_Node $node, \PHPParser_Node $parent = null) { // Consider only non-dynamic variables in this pass. if (!$node instanceof \PHPParser_Node_Expr_Variable || !is_string($node->name)) { return; } // We ignore PHP globals. if (NodeUtil::isSuperGlobal($node)) { return; } // Ignore variables which are defined here. if ($parent instanceof \PHPParser_Node_Expr_Assign && $parent->var === $node) { return; } if (!$t->getScope()->isDeclared($node->name)) { if ($bestName = CheckForTyposPass::getMostSimilarName($node->name, $t->getScope()->getVarNames())) { $this->phpFile->addComment($node->getLine(), Comment::error('typos.mispelled_variable_name', 'The variable ``%offending_variable_name%`` does not exist. Did you mean ``%closest_variable_name%``?', array('offending_variable_name' => '$' . $node->name, 'closest_variable_name' => '$' . $bestName))); } else { $this->phpFile->addComment($node->getLine(), Comment::warning('usage.undeclared_variable', 'The variable ``%variable_name%`` does not exist. Did you forget to declare it?', array('variable_name' => '$' . $node->name))); } return; } if ($parent instanceof \PHPParser_Node_Expr_ArrayDimFetch && $node->getAttribute('array_initializing_variable') && $parent->var === $node) { $this->phpFile->addComment($node->getLine(), Comment::warning('usage.non_initialized_array', '``%array_fetch_expr%`` was never initialized. Although not strictly required by PHP, it is generally a good practice to add ``%array_fetch_expr% = array();`` before regardless.', array('array_fetch_expr' => self::$prettyPrinter->prettyPrintExpr($node)))); } }
public function visit(NodeTraversal $t, \PHPParser_Node $node, \PHPParser_Node $parent = null) { switch (true) { case $node instanceof \PHPParser_Node_Expr_Variable: if (NodeUtil::isSuperGlobal($node)) { return; } if (is_string($node->name)) { $this->checkNaming($node->getLine(), '$' . $node->name, $node->name, 'local_variable'); } break; case $node instanceof \PHPParser_Node_Stmt_PropertyProperty: $this->checkNaming($node->getLine(), '$' . $node->name, $node->name, 'property_name'); break; case $node instanceof \PHPParser_Node_Stmt_Function: case $node instanceof \PHPParser_Node_Stmt_ClassMethod: $function = $this->typeRegistry->getFunctionByNode($node); // If a class method is constrained by a contract of an interface, or an abstract // class, then there is no point in adding warnings for them. if ($function instanceof ClassMethod && $function->isConstrainedByContract()) { break; } $this->checkNaming($node->getLine(), 'function ' . $node->name . '()', $node->name, 'method_name'); if (null !== $function && null !== ($returnType = $function->getReturnType()) && $returnType->isBooleanType()) { $this->checkNaming($node->getLine(), 'function ' . $node->name . '()', $node->name, 'isser_method_name'); } $this->checkParameters($node->params); break; case $node instanceof \PHPParser_Node_Expr_Closure: $this->checkParameters($node->params); break; case NodeUtil::isMethodContainer($node): $class = $this->typeRegistry->getClassByNode($node)->toMaybeObjectType(); if ($class) { $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'type_name'); if ($class->isInterface()) { $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'interface_name'); } elseif ($class instanceof Clazz) { if ($class->isUtilityClass()) { $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'utility_class_name'); } elseif ($class->isAbstract()) { $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'abstract_class_name'); } // No Else-If here as there might be an abstract exception. // TODO: isSubtype needs to return a TernaryValue so that we // can decide here what to do in the unknown case. // if ($class->isSubTypeOf($this->typeRegistry->getClassOrCreate('Exception'))) { // $this->checkNaming($node->getLine(), $class->getShortName(), $class->getShortName(), 'exception_name'); // } } // The original check only allows final classes to have a private // constructor. We also allow the constructor to be private if it // is declared final, and the class is declared abstract. This is // for example a common practice for utility classes. $method = $class->getMethod('__construct'); if (null !== $method && $method->isPrivate() && !$class->isFinal() && (!$method->isFinal() || !$class->isAbstract())) { if (($method = $class->getMethod('__construct')) && $method->isPrivate() && !$class->isFinal() && (!$method->isFinal() || !$class->isAbstract())) { if ($method->isFinal()) { if ($class->isUtilityClass()) { $this->phpFile->addComment($node->getLine(), Comment::warning('coding_style.non_abstract_util_class', 'Since you have declared the constructor as final, and this seems like a utility class, maybe you should also declare the class as abstract.')); } else { if (null === $method->getAstNode()) { break; } $this->phpFile->addComment($method->getAstNode()->getLine(), Comment::warning('coding_style.non_util_class_with_final_private_constructor', 'Instead of declaring the constructor as final, maybe you should declare the entire class as final.')); } } elseif ($class->isAbstract()) { if ($class->isUtilityClass()) { $this->phpFile->addComment($method->getAstNode()->getLine(), Comment::warning('coding_style.util_class_with_non_final_constructor', 'Since you have declared this class abstract, and the constructor is private, maybe you should also declare the constructor as final.')); } else { $this->phpFile->addComment($method->getAstNode()->getLine(), Comment::warning('coding_style.abstract_non_util_class_with_private_constructor', 'Something seems to be off here. Are you sure you want to declare the constructor as private, and the class as abstract?')); } } else { $this->phpFile->addComment($node->getLine(), Comment::warning('coding_style.non_final_class_with_private_constructor', 'Since you have declared the constructor as private, maybe you should also declare the class as final.')); } } } } break; } }