Navigation Menu

Skip to content

Commit

Permalink
[fixes #19875155] Implement static closures
Browse files Browse the repository at this point in the history
  • Loading branch information
manuelpichler committed Oct 19, 2011
1 parent e4e5d5e commit 1e24a34
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 14 deletions.
45 changes: 43 additions & 2 deletions src/main/php/PHP/Depend/Code/ASTClosure.php
Expand Up @@ -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 <b>TRUE</b> when the closure was declared as
* followed:
*
* <code>
* $closure = static function( $e ) {
* return pow( $e, 2 );
* }
* </code>
*
* And it will return <b>FALSE</b> when we declare the closure as usual:
*
* <code>
* $closure = function( $e ) {
* return pow( $e, 2 );
* }
* </code>
*
* @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.
Expand All @@ -114,6 +155,6 @@ public function accept(PHP_Depend_Code_ASTVisitorI $visitor, $data = null)
*/
protected function getMetadataSize()
{
return 6;
return 7;
}
}
}
22 changes: 19 additions & 3 deletions src/main/php/PHP/Depend/Parser.php
Expand Up @@ -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:
* <code>
* function foo() {
* // ------------------------------
* static $foo, $bar, $baz = null;
* // ------------------------------
* }
* </code>
*
*
* Static method invocation:
* <code>
* class Foo {
* public function baz() {
* // ----------------
Expand All @@ -5379,6 +5383,13 @@ private function _parseConstantDeclarator()
* }
* </code>
*
* Static closure declaration:
* <code>
* $closure = static function($x, $y) {
* return ($x * $y);
* };
* </code>
*
* @return PHP_Depend_Code_ASTConstant
* @throws PHP_Depend_Parser_Exception When an error occured during the
* parsing process.
Expand All @@ -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);
Expand Down
157 changes: 148 additions & 9 deletions src/test/php/PHP/Depend/Code/ASTClosureTest.php
Expand Up @@ -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());
}

/**
Expand All @@ -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());
}

/**
Expand All @@ -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:
* <code>
* return function($x, $y) {
* return pow($x, $y);
* }
* </code>
*
* @return void
*/
public function testIsStaticReturnsFalseForNonStaticClosure()
{
$closure = $this->_getFirstClosureInFunction();
$this->assertFalse($closure->isStatic());
}

/**
* testIsStaticReturnsTrueForStaticClosure
*
* Source:
* <code>
* return static function($x, $y) {
* return pow($x, $y);
* }
* </code>
*
* @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()));
}

/**
Expand Down Expand Up @@ -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));
}

/**
Expand Down Expand Up @@ -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());
}

/**
Expand All @@ -202,4 +341,4 @@ private function _getFirstClosureInFunction()
PHP_Depend_Code_ASTClosure::CLAZZ
);
}
}
}
@@ -0,0 +1,7 @@
<?php
function testIsStaticReturnsFalseForNonStaticClosure()
{
return function($x, $y) {
return pow($x, $y);
};
}
@@ -0,0 +1,9 @@
<?php
function testIsStaticReturnsTrueForStaticClosure()
{
$closure = static function($x, $y) {
return pow($x, $y);
};
var_dump($closure(2, 2));
}
testIsStaticReturnsTrueForStaticClosure();
@@ -0,0 +1,7 @@
<?php
function testReturnsByReferenceReturnsFalseByDefaultForStaticClosure()
{
return static function ($x, $y) {
return pow($x, $y);
};
}
@@ -0,0 +1,7 @@
<?php
function testReturnsByReferenceReturnsTrueForStaticClosure()
{
return static function &($x, $y) {
return pow($x, $y);
};
}
@@ -0,0 +1,8 @@
<?php
function testStaticClosureHasExpectedEndColumn()
{
return static
function($x, $y) {
return ($x * $y);
};
}
@@ -0,0 +1,8 @@
<?php
function testStaticClosureHasExpectedEndLine()
{
return static
function($x, $y) {
return ($x * $y);
};
}
@@ -0,0 +1,8 @@
<?php
function testStaticClosureHasExpectedStartColumn()
{
return static
function($x, $y) {
return ($x * $y);
};
}
@@ -0,0 +1,8 @@
<?php
function testStaticClosureHasExpectedStartLine()
{
return static
function($x, $y) {
return ($x * $y);
};
}

0 comments on commit 1e24a34

Please sign in to comment.