diff --git a/src/main/php/PHP/Depend/Code/ASTClosure.php b/src/main/php/PHP/Depend/Code/ASTClosure.php index f5f09298a..46bad2415 100644 --- a/src/main/php/PHP/Depend/Code/ASTClosure.php +++ b/src/main/php/PHP/Depend/Code/ASTClosure.php @@ -90,6 +90,47 @@ public function setReturnsByReference($returnsReference) $this->setMetadataBoolean(5, (boolean) $returnsReference); } + /** + * Returns whether this closure was defined as static or not. + * + * This method will return TRUE when the closure was declared as + * followed: + * + * + * $closure = static function( $e ) { + * return pow( $e, 2 ); + * } + * + * + * And it will return FALSE when we declare the closure as usual: + * + * + * $closure = function( $e ) { + * return pow( $e, 2 ); + * } + * + * + * @return boolean + * @since 0.11.0 + */ + public function isStatic() + { + return $this->getMetadataBoolean(6); + } + + /** + * This method can be used to flag this closure instance as static. + * + * @param boolean $static Whether this closure is static or not. + * + * @return void + * @since 0.11.0 + */ + public function setStatic($static) + { + $this->setMetadataBoolean(6, (boolean) $static); + } + /** * Accept method of the visitor design pattern. This method will be called * by a visitor during tree traversal. @@ -114,6 +155,6 @@ public function accept(PHP_Depend_Code_ASTVisitorI $visitor, $data = null) */ protected function getMetadataSize() { - return 6; + return 7; } -} \ No newline at end of file +} diff --git a/src/main/php/PHP/Depend/Parser.php b/src/main/php/PHP/Depend/Parser.php index 5f300fef6..3fa761124 100644 --- a/src/main/php/PHP/Depend/Parser.php +++ b/src/main/php/PHP/Depend/Parser.php @@ -5354,17 +5354,21 @@ private function _parseConstantDeclarator() } /** - * This method parses a static variable declaration list or a member primary - * prefix invoked in the static context of a class. + * This method parses a static variable declaration list, a member primary + * prefix invoked in the static context of a class or it parses a static + * closure declaration. * + * Static variable: * * function foo() { * // ------------------------------ * static $foo, $bar, $baz = null; * // ------------------------------ * } + * * - * + * Static method invocation: + * * class Foo { * public function baz() { * // ---------------- @@ -5379,6 +5383,13 @@ private function _parseConstantDeclarator() * } * * + * Static closure declaration: + * + * $closure = static function($x, $y) { + * return ($x * $y); + * }; + * + * * @return PHP_Depend_Code_ASTConstant * @throws PHP_Depend_Parser_Exception When an error occured during the * parsing process. @@ -5404,6 +5415,11 @@ private function _parseStaticVariableDeclarationOrMemberPrimaryPrefix() $prefix = $this->_parseStaticMemberPrimaryPrefix($static); return $this->_setNodePositionsAndReturn($prefix); + } else if ($tokenType === self::T_FUNCTION) { + $closure = $this->_parseClosureDeclaration(); + $closure->setStatic(true); + + return $this->_setNodePositionsAndReturn($closure); } $declaration = $this->_parseStaticVariableDeclaration($token); diff --git a/src/test/php/PHP/Depend/Code/ASTClosureTest.php b/src/test/php/PHP/Depend/Code/ASTClosureTest.php index 7f3dac8eb..00b40f68b 100644 --- a/src/test/php/PHP/Depend/Code/ASTClosureTest.php +++ b/src/test/php/PHP/Depend/Code/ASTClosureTest.php @@ -77,7 +77,18 @@ class PHP_Depend_Code_ASTClosureTest extends PHP_Depend_Code_ASTNodeTest public function testReturnsByReferenceReturnsFalseByDefault() { $closure = $this->_getFirstClosureInFunction(); - self::assertFalse($closure->returnsByReference()); + $this->assertFalse($closure->returnsByReference()); + } + + /** + * testReturnsByReferenceReturnsFalseByDefaultForStaticClosure + * + * @return void + */ + public function testReturnsByReferenceReturnsFalseByDefaultForStaticClosure() + { + $closure = $this->_getFirstClosureInFunction(); + $this->assertFalse($closure->returnsByReference()); } /** @@ -88,7 +99,18 @@ public function testReturnsByReferenceReturnsFalseByDefault() public function testReturnsByReferenceReturnsTrueForClosure() { $closure = $this->_getFirstClosureInFunction(); - self::assertTrue($closure->returnsByReference()); + $this->assertTrue($closure->returnsByReference()); + } + + /** + * testReturnsByReferenceReturnsTrueForStaticClosure + * + * @return void + */ + public function testReturnsByReferenceReturnsTrueForStaticClosure() + { + $closure = $this->_getFirstClosureInFunction(); + $this->assertTrue($closure->returnsByReference()); } /** @@ -99,7 +121,91 @@ public function testReturnsByReferenceReturnsTrueForClosure() public function testReturnsByReferenceReturnsTrueForAssignedClosure() { $closure = $this->_getFirstClosureInFunction(); - self::assertTrue($closure->returnsByReference()); + $this->assertTrue($closure->returnsByReference()); + } + + /** + * testIsStaticReturnsFalseByDefault + * + * @return void + */ + public function testIsStaticReturnsFalseByDefault() + { + $closure = new PHP_Depend_Code_ASTClosure(); + $this->assertFalse($closure->isStatic()); + } + + /** + * testIsStaticReturnsTrueWhenSetToTrue + * + * @return void + */ + public function testIsStaticReturnsTrueWhenSetToTrue() + { + $closure = new PHP_Depend_Code_ASTClosure(); + $closure->setStatic(true); + + $this->assertTrue($closure->isStatic()); + } + + /** + * testIsStaticReturnsFalseWhenSetToFalse + * + * @return void + */ + public function testIsStaticReturnsFalseWhenSetToFalse() + { + $closure = new PHP_Depend_Code_ASTClosure(); + $closure->setStatic(false); + + $this->assertFalse($closure->isStatic()); + } + + /** + * testIsStaticReturnsFalseForNonStaticClosure + * + * Source: + * + * return function($x, $y) { + * return pow($x, $y); + * } + * + * + * @return void + */ + public function testIsStaticReturnsFalseForNonStaticClosure() + { + $closure = $this->_getFirstClosureInFunction(); + $this->assertFalse($closure->isStatic()); + } + + /** + * testIsStaticReturnsTrueForStaticClosure + * + * Source: + * + * return static function($x, $y) { + * return pow($x, $y); + * } + * + * + * @return void + */ + public function testIsStaticReturnsTrueForStaticClosure() + { + $closure = $this->_getFirstClosureInFunction(); + $this->assertTrue($closure->isStatic()); + } + + /** + * testClosureContainsExpectedNumberChildNodes + * + * @return void + */ + public function testClosureContainsExpectedNumberChildNodes() + { + $closure = $this->_getFirstClosureInFunction(); + $this->assertEquals(2, count($closure->getChildren())); } /** @@ -132,7 +238,7 @@ public function testAcceptReturnsReturnValueOfVisitMethod() ->will($this->returnValue(42)); $node = new PHP_Depend_Code_ASTClosure(); - self::assertEquals(42, $node->accept($visitor)); + $this->assertEquals(42, $node->accept($visitor)); } /** @@ -180,14 +286,47 @@ public function testClosureHasExpectedEndColumn() } /** - * testClosureContainsExpectedNumberChildNodes + * testStaticClosureHasExpectedStartLine * * @return void */ - public function testClosureContainsExpectedNumberChildNodes() + public function testStaticClosureHasExpectedStartLine() { - $closure = $this->_getFirstClosureInFunction(); - $this->assertEquals(2, count($closure->getChildren())); + $label = $this->_getFirstClosureInFunction(); + $this->assertEquals(4, $label->getStartLine()); + } + + /** + * testStaticClosureHasExpectedEndLine + * + * @return void + */ + public function testStaticClosureHasExpectedEndLine() + { + $label = $this->_getFirstClosureInFunction(); + $this->assertEquals(7, $label->getEndLine()); + } + + /** + * testStaticClosureHasExpectedStartColumn + * + * @return void + */ + public function testStaticClosureHasExpectedStartColumn() + { + $label = $this->_getFirstClosureInFunction(); + $this->assertEquals(12, $label->getStartColumn()); + } + + /** + * testStaticClosureHasExpectedEndColumn + * + * @return void + */ + public function testStaticClosureHasExpectedEndColumn() + { + $label = $this->_getFirstClosureInFunction(); + $this->assertEquals(9, $label->getEndColumn()); } /** @@ -202,4 +341,4 @@ private function _getFirstClosureInFunction() PHP_Depend_Code_ASTClosure::CLAZZ ); } -} \ No newline at end of file +} diff --git a/src/test/resources/files/Code/ASTClosure/testIsStaticReturnsFalseForNonStaticClosure.php b/src/test/resources/files/Code/ASTClosure/testIsStaticReturnsFalseForNonStaticClosure.php new file mode 100644 index 000000000..d5a54ec6c --- /dev/null +++ b/src/test/resources/files/Code/ASTClosure/testIsStaticReturnsFalseForNonStaticClosure.php @@ -0,0 +1,7 @@ +