/** * Will iterate the tokens looking for protected methods and variables, once * found it will validate the name of it's parent starts with an underscore. * * @param Testable $testable The testable object * @return void */ public function apply($testable, array $config = array()) { $message = 'Protected method {:name} must start with an underscore'; $tokens = $testable->tokens(); $filtered = $testable->findAll(array(T_PROTECTED)); foreach ($filtered as $tokenId) { $token = $tokens[$tokenId]; $parent = $testable->findNext(array(T_FUNCTION, T_VARIABLE), $tokenId); $parentLabel = Parser::label($parent, $tokens); if (substr($parentLabel, 0, 1) !== '_') { $classTokenId = $testable->findNext(array(T_STRING), $token['parent']); $classname = $tokens[$classTokenId]['content']; $params = array('message' => String::insert($message, array('name' => $parentLabel)), 'line' => $token['line']); if ($this->_strictMode($classname)) { $this->addViolation($params); } else { $this->addWarning($params); } } } }
/** * Will iterate tokens looking for comments and if found will determine the regex * to test the comment against. * * @param Testable $testable The testable object * @return void */ public function apply($testable, array $config = array()) { $tokens = $testable->tokens(); $lines = $testable->lines(); $lineCache = $testable->lineCache(); $inspectable = array(T_CLASS, T_VARIABLE, T_FUNCTION, T_CONST, T_DOUBLE_COLON); foreach ($testable->findAll(array(T_DOC_COMMENT)) as $tokenId) { $token = $tokens[$tokenId]; $nextLine = $token['line'] + count(preg_split('/\\r\\n|\\r|\\n/', $token['content'])); $parentId = false; if (isset($lineCache[$nextLine])) { $parentId = $testable->findNext($inspectable, $lineCache[$nextLine]); } if ($parentId === false && $token['line'] !== 2) { $this->addViolation(array('message' => 'Docblocks should only be at the beginning of the page or ' . 'before a class/function or static call.', 'line' => $token['line'])); continue; } $parent = $tokens[$parentId]; $content = null; if ($token['line'] === 2) { $match = 'PAGE'; } else { switch ($parent['id']) { case T_CLASS: $match = 'CLASS'; break; case T_DOUBLE_COLON: case T_FUNCTION: $match = 'METHOD'; break; case T_VARIABLE: case T_CONST: $match = 'VARIABLE'; break; } } if (in_array($parent['id'], array(T_FUNCTION, T_VARIABLE), true)) { $content .= $tokens[$tokenId - 1]['content']; } $content .= $token['content']; $pattern = $this->compilePattern($match); $correctFormat = preg_match($this->compilePattern($match), $content) === 1; $hasTags = preg_match($this->compilePattern('HAS_TAGS'), $content) === 1; $correctTagFormat = preg_match($this->compilePattern('TAG_FORMAT'), $content) === 1; if (!$correctFormat) { $this->addViolation(array('message' => 'Docblocks are in the incorrect format.', 'line' => $token['line'])); } elseif ($hasTags && !$correctTagFormat) { $this->addViolation(array('hasTags' => (int) $hasTags, 'correctTagFormat' => (int) $correctTagFormat, 'tagFormat' => $this->compilePattern('TAG_FORMAT'), 'message' => 'Tags should be last and have a blank docblock line.', 'line' => $token['line'])); } } }
/** * Will iterate the tokens looking for functions validating they have the * correct camelBack naming style. * * @param Testable $testable The testable object * @return void */ public function apply($testable, array $config = array()) { $tokens = $testable->tokens(); $filtered = $testable->findAll(array(T_FUNCTION)); foreach ($filtered as $key) { $token = $tokens[$key]; $label = Parser::label($key, $tokens); $modifiers = Parser::modifiers($key, $tokens); $isClosure = Parser::closure($key, $tokens); if (in_array($label, $this->_magicMethods)) { continue; } if ($testable->findNext(array(T_PROTECTED), $modifiers) !== false) { $label = preg_replace('/^_/', '', $label); } if (!$isClosure && $label !== Inflector::camelize($label, false)) { $this->addViolation(array('message' => 'Function "' . $label . '" is not in camelBack style', 'line' => $tokens[$tokens[$key]['parent']]['line'])); } } }
/** * Will iterate all the tokens looking for tokens in inspectableTokens * The token needs an access modifier if it is a T_FUNCTION or T_VARIABLE * and is in the first level of T_CLASS. This prevents functions and variables * inside methods and outside classes to register violations. * * @param Testable $testable The testable object * @return void */ public function apply($testable, array $config = array()) { $message = '{:name} has no declared visibility.'; $tokens = $testable->tokens(); $classes = $testable->findAll(array(T_CLASS)); $filtered = $testable->findAll($this->inspectableTokens); foreach ($classes as $classId) { $children = $tokens[$classId]['children']; foreach ($children as $member) { if (!in_array($member, $filtered)) { continue; } $modifiers = Parser::modifiers($member, $tokens); $visibility = $testable->findNext($this->findTokens, $modifiers); if ($visibility === false) { $token = $tokens[$member]; $this->addViolation(array('modifiers' => $modifiers, 'message' => String::insert($message, $token), 'line' => $token['line'])); } } } }