diff --git a/.phpsa.yml b/.phpsa.yml index 177ede5d..34418cca 100644 --- a/.phpsa.yml +++ b/.phpsa.yml @@ -91,4 +91,6 @@ phpsa: enabled: true yoda_condition: enabled: true + return_and_yield_in_one_method: + enabled: true diff --git a/docs/05_Analyzers.md b/docs/05_Analyzers.md index b4cbce9d..b62ba292 100644 --- a/docs/05_Analyzers.md +++ b/docs/05_Analyzers.md @@ -36,7 +36,7 @@ Checks for casts that try to cast a type to itself. #### CompareWithArray -Checks for `{type array} > 1` and similar and suggests use of `count()`. +Checks for `{type array} > 1` and similar and suggests use of `count()`. #### ConstantNaming @@ -130,6 +130,10 @@ Checks for use of old rand, srand, getrandmax functions and suggests alternative Checks that regular expressions are syntactically correct. +#### ReturnAndYieldInOneMethod + +Checks for using return and yield statements in a one method and discourages it. + #### StaticUsage Discourages the use of static variables (not properties). diff --git a/src/Analyzer/Factory.php b/src/Analyzer/Factory.php index c1a7a788..1f777143 100644 --- a/src/Analyzer/Factory.php +++ b/src/Analyzer/Factory.php @@ -97,6 +97,7 @@ private static function getStatementPasses() AnalyzerPass\Statement\StaticUsage::class, AnalyzerPass\Statement\OptionalParamBeforeRequired::class, AnalyzerPass\Statement\YodaCondition::class, + AnalyzerPass\Statement\ReturnAndYieldInOneMethod::class, ]; } diff --git a/src/Analyzer/Helper/ResolveExpressionTrait.php b/src/Analyzer/Helper/ResolveExpressionTrait.php index e2e592b4..c9765797 100644 --- a/src/Analyzer/Helper/ResolveExpressionTrait.php +++ b/src/Analyzer/Helper/ResolveExpressionTrait.php @@ -34,18 +34,30 @@ public function resolveFunctionName(FuncCall $funcCall, Context $context) } /** + * Finds statements of the given class name. + * * @param \PhpParser\Node[] $nodes - * @return \PhpParser\Node\Stmt\Return_ + * @param string $stmtClass + * @return \PhpParser\Node\Stmt */ - protected function findReturnStatement(array $nodes) + protected function findStatement(array $nodes, $stmtClass) { foreach ($this->traverseArray($nodes) as $node) { - if ($node instanceof Return_) { + if ($node instanceof $stmtClass) { yield $node; } } } + /** + * @param \PhpParser\Node[] $nodes + * @return \PhpParser\Node\Stmt\Return_ + */ + protected function findReturnStatement(array $nodes) + { + return $this->findStatement($nodes, Return_::class); + } + /** * For the code above * Я атеист, но когда я начинал это писать, только Бог и я понимали, что я делаю diff --git a/src/Analyzer/Pass/Statement/ReturnAndYieldInOneMethod.php b/src/Analyzer/Pass/Statement/ReturnAndYieldInOneMethod.php new file mode 100644 index 00000000..efa339de --- /dev/null +++ b/src/Analyzer/Pass/Statement/ReturnAndYieldInOneMethod.php @@ -0,0 +1,61 @@ +returnStatementExists($stmt) && $this->yieldStatementExists($stmt)) { + $context->notice('return_and_yield_in_one_method', 'Do not use return and yield in a one method', $stmt); + return true; + } + + return false; + } + + /** + * @param Stmt $node + * + * @return bool + */ + private function returnStatementExists(Stmt $node) + { + return (bool)$this->findReturnStatement([$node])->current(); + } + + /** + * @param Stmt $node + * + * @return bool + */ + private function yieldStatementExists(Stmt $node) + { + return (bool)$this->findStatement([$node], Yield_::class)->current(); + } + + /** + * @return array + */ + public function getRegister() + { + return [ + Stmt\ClassMethod::class, + ]; + } +} diff --git a/tests/analyze-fixtures/Statement/ReturnAndYieldInOneMethod.php b/tests/analyze-fixtures/Statement/ReturnAndYieldInOneMethod.php new file mode 100644 index 00000000..803c93e6 --- /dev/null +++ b/tests/analyze-fixtures/Statement/ReturnAndYieldInOneMethod.php @@ -0,0 +1,44 @@ + +---------------------------- +[ + { + "type": "return_and_yield_in_one_method", + "message": "Do not use return and yield in a one method", + "file": "ReturnAndYieldInOneMethod.php", + "line": 6 + } +]