Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Fix code reflection - getBody/getContents method #5245

Closed
wants to merge 15 commits into from

6 participants

@blanchonvincent

Zend\Code\Reflection getBody function is often broken with some code format

  • implement getBody in FunctionReflection
  • fix getBody in MethodReflection
  • fix getContents in FunctionReflection
  • fix getContents in MethodReflection
@blanchonvincent blanchonvincent referenced this pull request in Ocramius/ProxyManager
Open

[TO BE MOVED] Parametric polymorphism proxy / Object method extensions #103

7 of 7 tasks complete
tests/ZendTest/Code/Reflection/TestAsset/closures.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Code

remove @package

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
tests/ZendTest/Code/Reflection/TestAsset/closures.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Code
+ */
+
+namespace ZendTest\Code\Reflection\TestAsset;
+
+$function1 = function()
+{

move open brace up and add space for PSR-2

no, it's deliberate :)

ok ^^

@Maks3w Collaborator
Maks3w added a note

@blanchonvincent Anyway, please add a comment advising that is deliberated (and explaining why) for prevent accidental changes in the future (mass changes, etc).

@blanchonvincent I think that brace at new line is one of the reasons that make travis failure instead of trailing_spaces.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@blanchonvincent

@Ocramius can you confirm that on this function :

function1()
{
    return 'foo';
}

getBody is :

return 'foo';

getContent is :

function1()
{
    return 'foo';
}

?

@Ocramius
Collaborator

@blanchonvincent never used that API - are there no other tests for it?

@blanchonvincent

@Ocramius The prototype is

public function getContents($includeDocBlock = true)

So, if the contents is :

{
   return ....;
}

what is the contents with docblock ? I think there is a bug, and the contents must be :

function foo()
{
   return ....;
}

and with docblock :

/**
 * bla bla bla
 */
function foo()
{
   return ....;
}
@Ocramius
Collaborator

@blanchonvincent yep, I agree on that. I'd just first check what the consumers of that method are before applying any change.

@blanchonvincent

@Ocramius, Ok, let me know

@Ocramius
Collaborator

@blanchonvincent no, I was suggesting you to grep for its usage :)

@blanchonvincent

@Ocramius, Look never used, and $useDockBlock param doesn't work, and lot of time, the function return an empty result ... so I fix that.

@blanchonvincent

PR is finished -- better code coverage & lot of fixs

@mwillbanks
Collaborator

@Ocramius since you did original review; could you please review a last time?

@Ocramius Ocramius commented on the diff
library/Zend/Code/Reflection/FunctionReflection.php
((29 lines not shown))
);
+
+ $functionLine = implode("\n", $lines);
+
+ $content = false;
+ if ($this->isClosure()) {
+ preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)?\s*\}#s', $functionLine, $matches);
@Ocramius Collaborator

Woah, this witchcraft needs a comment :-)

@Ocramius Collaborator

Does this handle also closures containing closures?

@weierophinney Owner

@Ocramius I don't see any reason why it wouldn't -- the body regex is looking for any number of terminated statements.

@Ocramius, yep, look at the tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Code/Reflection/FunctionReflection.php
((29 lines not shown))
);
+
+ $functionLine = implode("\n", $lines);
+
+ $content = false;
+ if ($this->isClosure()) {
+ preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)?\s*\}#s', $functionLine, $matches);
+ if (isset($matches[0])) {
+ $content = $matches[0];
+ }
+ } else {
+ $name = substr($this->getName(), strrpos($this->getName(), '\\')+1);
+ preg_match('#function\s+' . $name . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)?}#', $functionLine, $matches);
@Ocramius Collaborator

Same here (comment)

@Ocramius Collaborator

$name should go through preg_quote

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Code/Reflection/FunctionReflection.php
((32 lines not shown))
+
+ $content = false;
+ if ($this->isClosure()) {
+ preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)?\s*\}#s', $functionLine, $matches);
+ if (isset($matches[0])) {
+ $content = $matches[0];
+ }
+ } else {
+ $name = substr($this->getName(), strrpos($this->getName(), '\\')+1);
+ preg_match('#function\s+' . $name . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)?}#', $functionLine, $matches);
+ if (isset($matches[0])) {
+ $content = $matches[0];
+ }
+ }
+
+ return $includeDocBlock && $this->getDocComment() ? $this->getDocComment() . "\n" . $content : $content;
@Ocramius Collaborator

Can you avoid calling $this->getDocComment() twice here? It's not about performance, but you can't trust $this->getDocComment() retrieving always the same result.

@Ocramius Collaborator

As an additional note: what if the separator between body and docblock is not \n (for example \n\n\n)? (may also not be relevant)

I think I can't catch if the separator is not a \n :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Ocramius Ocramius commented on the diff
library/Zend/Code/Reflection/FunctionReflection.php
((5 lines not shown))
return new DocBlockReflection('@return ' . $tag->getDescription());
}
+ /**
+ * Get method body
+ *
+ * @return string
+ */
+ public function getBody()
+ {
+ $fileName = $this->getFileName();
+ if (false === $fileName) {
+ throw new Exception\InvalidArgumentException(
+ 'Cannot determine internals functions body'
@Ocramius Collaborator

What if the class is eval'd?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Ocramius Ocramius commented on the diff
library/Zend/Code/Reflection/FunctionReflection.php
((6 lines not shown))
* @return string
*/
public function getContents($includeDocBlock = true)
{
- return implode("\n",
- array_splice(
- file($this->getFileName()),
- $this->getStartLine($includeDocBlock),
- ($this->getEndLine() - $this->getStartLine()),
- true
- )
+ $fileName = $this->getFileName();
+ if (false === $fileName) {
+ throw new Exception\InvalidArgumentException(
+ 'Cannot determine internals functions contents'
@Ocramius Collaborator

What if the function is eval'd?

ok, test added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Ocramius Ocramius commented on the diff
library/Zend/Code/Reflection/FunctionReflection.php
((18 lines not shown))
+ 'Cannot determine internals functions body'
+ );
+ }
+
+ $lines = array_slice(
+ file($fileName, FILE_IGNORE_NEW_LINES),
+ $this->getStartLine() - 1,
+ ($this->getEndLine() - ($this->getStartLine() - 1)),
+ true
+ );
+
+ $functionLine = implode("\n", $lines);
+
+ $body = false;
+ if ($this->isClosure()) {
+ preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)\s*\}#s', $functionLine, $matches);
@Ocramius Collaborator

Same remarks as above

@Ocramius Collaborator

Also: these regexes look constant. Can you move them to either a class constant or a private property?

@weierophinney Owner

They're not -- there are subtle differences in what each is matching.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Ocramius Ocramius commented on the diff
library/Zend/Code/Reflection/FunctionReflection.php
((24 lines not shown))
+ $this->getStartLine() - 1,
+ ($this->getEndLine() - ($this->getStartLine() - 1)),
+ true
+ );
+
+ $functionLine = implode("\n", $lines);
+
+ $body = false;
+ if ($this->isClosure()) {
+ preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)\s*\}#s', $functionLine, $matches);
+ if (isset($matches[2])) {
+ $body = $matches[2];
+ }
+ } else {
+ $name = substr($this->getName(), strrpos($this->getName(), '\\')+1);
+ preg_match('#function\s+' . $name . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)}#', $functionLine, $matches);
@Ocramius Collaborator

Same remarks as above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Code/Reflection/FunctionReflection.php
((5 lines not shown))
return new DocBlockReflection('@return ' . $tag->getDescription());
}
+ /**
+ * Get method body
+ *
+ * @return string
@Ocramius Collaborator

The result may be false

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Code/Reflection/MethodReflection.php
((19 lines not shown))
- return implode("\n", array_splice($fileContents, $startNum, $endNum, true));
+ $lines = array_slice(
+ file($fileName, FILE_IGNORE_NEW_LINES),
+ $this->getStartLine() - 1,
+ ($this->getEndLine() - ($this->getStartLine() - 1)),
+ true
+ );
+
+ $functionLine = implode("\n", $lines);
+ preg_match('#[(public|protected|private|abstract|final|static)\s*]+function\s+' . $this->getName() . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)?}#s', $functionLine, $matches);
@Ocramius Collaborator

Split this line

@Ocramius Collaborator

a function doesn't necessarily have a visibility descriptor:

class Foo
{
    function bar()
    {
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Code/Reflection/MethodReflection.php
((22 lines not shown))
+ file($fileName, FILE_IGNORE_NEW_LINES),
+ $this->getStartLine() - 1,
+ ($this->getEndLine() - ($this->getStartLine() - 1)),
+ true
+ );
+
+ $functionLine = implode("\n", $lines);
+ preg_match('#[(public|protected|private|abstract|final|static)\s*]+function\s+' . $this->getName() . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)?}#s', $functionLine, $matches);
+
+ if (!isset($matches[0])) {
+ return false;
+ }
+
+ $content = $matches[0];
+
+ return $includeDocBlock && $this->getDocComment() ? $this->getDocComment() . "\n" . $content : $content;
@Ocramius Collaborator

Same as above - don't trust getDocComment()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Ocramius Ocramius commented on the diff
library/Zend/Code/Reflection/MethodReflection.php
@@ -134,27 +152,30 @@ public function getContents($includeDocBlock = true)
*/
public function getBody()
{
+ $fileName = $this->getFileName();
+ if (false === $fileName) {
+ throw new Exception\InvalidArgumentException(
+ 'Cannot determine internals functions body'
@Ocramius Collaborator

eval'd code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
library/Zend/Code/Reflection/MethodReflection.php
((18 lines not shown))
true
);
- $firstLine = array_shift($lines);
+ $functionLine = implode("\n", $lines);
+ preg_match('#[(public|protected|private|abstract|final|static)\s*]+function\s+' . $this->getName() . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)}#s', $functionLine, $matches);
@Ocramius Collaborator

preg_quote?

@Ocramius Collaborator

Same comment about the visibility descriptors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Ocramius Ocramius commented on the diff
...s/ZendTest/Code/Reflection/FunctionReflectionTest.php
@@ -32,7 +32,187 @@ public function testParemeterReturn()
public function testFunctionDocBlockReturn()
{
require_once __DIR__ . '/TestAsset/functions.php';
- $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function6');
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function3');
@Ocramius Collaborator

Can you avoid altering the test? (a reason why the test was modified is also ok for me)

yep because i renamed function :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Ocramius Ocramius commented on the diff
tests/ZendTest/Code/Reflection/MethodReflectionTest.php
((12 lines not shown))
public function testGetBodyReturnsCorrectBody()
{
- $body = ' //we need a multi-line method body.
@Ocramius Collaborator

Also here, can you avoid modifying the existing test?

I updated the test because it fail with the function update. There was a bug with \n, so i just add a \n

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Maks3w
Collaborator

@blanchonvincent Please rebase the PR for fix merge conflicts

@weierophinney weierophinney referenced this pull request from a commit
@weierophinney weierophinney [#5245] CS fixes
- trailing whitespace, braces
- Added functions.php to the exclude list for php-cs-fixer, as the tests are
  testing specific formatting issues.
76074d4
@weierophinney

Merged to develop for release with 2.3.0, as it represents new functionality. I took care of the merge conflicts.

@stefanotorresi stefanotorresi referenced this pull request from a commit in stefanotorresi/zf2
@stefanotorresi stefanotorresi Revert "[#5245] CS fixes"
This reverts commit 76074d4.
7c5c8b0
@stefanotorresi stefanotorresi referenced this pull request
Merged

CS fix for #5245 #5391

@weierophinney weierophinney referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@weierophinney weierophinney referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@weierophinney weierophinney referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@weierophinney weierophinney referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
@weierophinney weierophinney referenced this pull request from a commit
Commit has since been removed from the repository and is no longer available.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
102 library/Zend/Code/Reflection/FunctionReflection.php
@@ -54,19 +54,53 @@ public function getStartLine($includeDocComment = false)
/**
* Get contents of function
*
- * @param bool $includeDocBlock
- * @return string
+ * @param bool $includeDocBlock
+ * @return string|bool
*/
public function getContents($includeDocBlock = true)
{
- return implode("\n",
- array_splice(
- file($this->getFileName()),
- $this->getStartLine($includeDocBlock),
- ($this->getEndLine() - $this->getStartLine()),
- true
- )
+ $fileName = $this->getFileName();
+ if (false === $fileName) {
+ throw new Exception\InvalidArgumentException(
+ 'Cannot determine internals functions contents'
@Ocramius Collaborator

What if the function is eval'd?

ok, test added

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ );
+ }
+
+ $startLine = $this->getStartLine();
+ $endLine = $this->getEndLine();
+
+ // eval'd protect
+ if (preg_match('#\((\d+)\) : eval\(\)\'d code$#', $fileName, $matches)) {
+ $fileName = preg_replace('#\(\d+\) : eval\(\)\'d code$#', '', $fileName);
+ $startLine = $endLine = $matches[1];
+ }
+
+ $lines = array_slice(
+ file($fileName, FILE_IGNORE_NEW_LINES),
+ $startLine - 1,
+ ($endLine - ($startLine - 1)),
+ true
);
+
+ $functionLine = implode("\n", $lines);
+
+ $content = false;
+ if ($this->isClosure()) {
+ preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)?\s*\}#s', $functionLine, $matches);
@Ocramius Collaborator

Woah, this witchcraft needs a comment :-)

@Ocramius Collaborator

Does this handle also closures containing closures?

@weierophinney Owner

@Ocramius I don't see any reason why it wouldn't -- the body regex is looking for any number of terminated statements.

@Ocramius, yep, look at the tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ if (isset($matches[0])) {
+ $content = $matches[0];
+ }
+ } else {
+ $name = substr($this->getName(), strrpos($this->getName(), '\\')+1);
+ preg_match('#function\s+' . preg_quote($name) . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)?}#', $functionLine, $matches);
+ if (isset($matches[0])) {
+ $content = $matches[0];
+ }
+ }
+
+ $docComment = $this->getDocComment();
+
+ return $includeDocBlock && $docComment ? $docComment . "\n" . $content : $content;
}
/**
@@ -104,9 +138,59 @@ public function getReturn()
}
$tag = $docBlock->getTag('return');
+
return new DocBlockReflection('@return ' . $tag->getDescription());
}
+ /**
+ * Get method body
+ *
+ * @return string|bool
+ */
+ public function getBody()
+ {
+ $fileName = $this->getFileName();
+ if (false === $fileName) {
+ throw new Exception\InvalidArgumentException(
+ 'Cannot determine internals functions body'
@Ocramius Collaborator

What if the class is eval'd?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ );
+ }
+
+ $startLine = $this->getStartLine();
+ $endLine = $this->getEndLine();
+
+ // eval'd protect
+ if (preg_match('#\((\d+)\) : eval\(\)\'d code$#', $fileName, $matches)) {
+ $fileName = preg_replace('#\(\d+\) : eval\(\)\'d code$#', '', $fileName);
+ $startLine = $endLine = $matches[1];
+ }
+
+ $lines = array_slice(
+ file($fileName, FILE_IGNORE_NEW_LINES),
+ $startLine - 1,
+ ($endLine - ($startLine - 1)),
+ true
+ );
+
+ $functionLine = implode("\n", $lines);
+
+ $body = false;
+ if ($this->isClosure()) {
+ preg_match('#function\s*\([^\)]*\)\s*(use\s*\([^\)]+\))?\s*\{(.*\;)\s*\}#s', $functionLine, $matches);
@Ocramius Collaborator

Same remarks as above

@Ocramius Collaborator

Also: these regexes look constant. Can you move them to either a class constant or a private property?

@weierophinney Owner

They're not -- there are subtle differences in what each is matching.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ if (isset($matches[2])) {
+ $body = $matches[2];
+ }
+ } else {
+ $name = substr($this->getName(), strrpos($this->getName(), '\\')+1);
+ preg_match('#function\s+' . $name . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)}#', $functionLine, $matches);
@Ocramius Collaborator

Same remarks as above

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ if (isset($matches[1])) {
+ $body = $matches[1];
+ }
+ }
+
+ return $body;
+ }
+
public function toString()
{
return $this->__toString();
View
66 library/Zend/Code/Reflection/MethodReflection.php
@@ -10,7 +10,6 @@
namespace Zend\Code\Reflection;
use ReflectionMethod as PhpReflectionMethod;
-use Zend\Code\Annotation\AnnotationCollection;
use Zend\Code\Annotation\AnnotationManager;
use Zend\Code\Scanner\AnnotationScanner;
use Zend\Code\Scanner\CachingFileScanner;
@@ -115,46 +114,71 @@ public function getParameters()
/**
* Get method contents
*
- * @param bool $includeDocBlock
- * @return string
+ * @param bool $includeDocBlock
+ * @return string|bool
*/
public function getContents($includeDocBlock = true)
{
- $fileContents = file($this->getFileName());
- $startNum = $this->getStartLine($includeDocBlock);
- $endNum = ($this->getEndLine() - $this->getStartLine());
+ $fileName = $this->getFileName();
+ if (false === $fileName) {
+ throw new Exception\InvalidArgumentException(
+ 'Cannot determine internals methods contents'
+ );
+ }
- return implode("\n", array_splice($fileContents, $startNum, $endNum, true));
+ $lines = array_slice(
+ file($fileName, FILE_IGNORE_NEW_LINES),
+ $this->getStartLine() - 1,
+ ($this->getEndLine() - ($this->getStartLine() - 1)),
+ true
+ );
+
+ $functionLine = implode("\n", $lines);
+ $name = preg_quote($this->getName());
+ preg_match('#[(public|protected|private|abstract|final|static)\s*]*function\s+' . $name . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)?}#s', $functionLine, $matches);
+
+ if (!isset($matches[0])) {
+ return false;
+ }
+
+ $content = $matches[0];
+ $docComment = $this->getDocComment();
+
+ return $includeDocBlock && $docComment ? $docComment . "\n" . $content : $content;
}
/**
* Get method body
*
- * @return string
+ * @return string|bool
*/
public function getBody()
{
+ $fileName = $this->getFileName();
+ if (false === $fileName) {
+ throw new Exception\InvalidArgumentException(
+ 'Cannot determine internals functions body'
@Ocramius Collaborator

eval'd code?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ );
+ }
+
$lines = array_slice(
- file($this->getDeclaringClass()->getFileName(), FILE_IGNORE_NEW_LINES),
- $this->getStartLine(),
- ($this->getEndLine() - $this->getStartLine()),
+ file($fileName, FILE_IGNORE_NEW_LINES),
+ $this->getStartLine() - 1,
+ ($this->getEndLine() - ($this->getStartLine() - 1)),
true
);
- $firstLine = array_shift($lines);
+ $functionLine = implode("\n", $lines);
+ $name = preg_quote($this->getName());
+ preg_match('#[(public|protected|private|abstract|final|static)\s*]*function\s+' . $name . '\s*\([^\)]*\)\s*{([^{}]+({[^}]+})*[^}]+)}#s', $functionLine, $matches);
- if (trim($firstLine) !== '{') {
- array_unshift($lines, $firstLine);
+ if (!isset($matches[1])) {
+ return false;
}
- $lastLine = array_pop($lines);
-
- if (trim($lastLine) !== '}') {
- array_push($lines, $lastLine);
- }
+ $body = $matches[1];
- // just in case we had code on the bracket lines
- return rtrim(ltrim(implode("\n", $lines), '{'), '}');
+ return $body;
}
public function toString()
View
190 tests/ZendTest/Code/Reflection/FunctionReflectionTest.php
@@ -32,7 +32,195 @@ public function testParemeterReturn()
public function testFunctionDocBlockReturn()
{
require_once __DIR__ . '/TestAsset/functions.php';
- $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function6');
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function3');
@Ocramius Collaborator

Can you avoid altering the test? (a reason why the test was modified is also ok for me)

yep because i renamed function :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
$this->assertInstanceOf('Zend\Code\Reflection\DocBlockReflection', $function->getDocBlock());
}
+
+ public function testInternalFunctionBodyReturn()
+ {
+ $function = new FunctionReflection('array_splice');
+ $this->setExpectedException('Zend\Code\Reflection\Exception\InvalidArgumentException');
+ $body = $function->getBody();
+ }
+
+ public function testFunctionBodyReturn()
+ {
+ require_once __DIR__ . '/TestAsset/functions.php';
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function1');
+ $body = $function->getBody();
+ $this->assertEquals("return 'function1';", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function4');
+ $body = $function->getBody();
+ $this->assertEquals("return 'function4';", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function5');
+ $body = $function->getBody();
+ $this->assertEquals("return 'function5';", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function6');
+ $body = $function->getBody();
+ $this->assertEquals("\$closure = function() { return 'bar'; };\n return 'function6';", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function7');
+ $body = $function->getBody();
+ $this->assertEquals("return 'function7';", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function8');
+ $body = $function->getBody();
+ $this->assertEquals("return 'function8';", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function9');
+ $body = $function->getBody();
+ $this->assertEquals("return 'function9';", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function10');
+ $body = $function->getBody();
+ $this->assertEquals("\$closure = function() { return 'function10'; }; return \$closure();", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function11');
+ $body = $function->getBody();
+ $this->assertEquals("return 'function11';", trim($body));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function12');
+ $body = $function->getBody();
+ $this->assertEquals("", trim($body));
+ }
+
+ public function testFunctionClosureBodyReturn()
+ {
+ require __DIR__ . '/TestAsset/closures.php';
+
+ $function = new FunctionReflection($function1);
+ $body = $function->getBody();
+ $this->assertEquals("return 'function1';", trim($body));
+
+ $function = new FunctionReflection($function2);
+ $body = $function->getBody();
+ $this->assertEquals("return 'function2';", trim($body));
+
+ $function = new FunctionReflection($function3);
+ $body = $function->getBody();
+ $this->assertEquals("return 'function3';", trim($body));
+
+ $function = new FunctionReflection($function4);
+ $body = $function->getBody();
+ $this->assertEquals("\$closure = function() { return 'bar'; };\n return 'function4';", trim($body));
+
+ $function5 = $list1['closure'];
+ $function = new FunctionReflection($function5);
+ $body = $function->getBody();
+ $this->assertEquals("return 'function5';", trim($body));
+
+ $function6 = $list2[0];
+ $function = new FunctionReflection($function6);
+ $body = $function->getBody();
+ $this->assertEquals("return 'function6';", trim($body));
+
+ $function7 = $list3[0];
+ $function = new FunctionReflection($function7);
+ $body = $function->getBody();
+ $this->assertEquals("return \$c = function() { return 'function7'; }; return \$c();", trim($body));
+
+ $function = new FunctionReflection($function8);
+ $body = $function->getBody();
+ $this->assertEquals("return 'function 8';", trim($body));
+
+ $function = new FunctionReflection($function9);
+ $body = $function->getBody();
+ $this->assertEquals("", trim($body));
+
+ $function = new FunctionReflection($function10);
+ $body = $function->getBody();
+ $this->assertEquals("return 'function10';", trim($body));
+ }
+
+ public function testInternalFunctionContentsReturn()
+ {
+ $function = new FunctionReflection('array_splice');
+ $this->setExpectedException('Zend\Code\Reflection\Exception\InvalidArgumentException');
+ $content = $function->getContents();
+ }
+
+ public function testFunctionContentsReturnWithoutDocBlock()
+ {
+ require_once __DIR__ . '/TestAsset/functions.php';
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function1');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function1()\n{\n return 'function1';\n}", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function4');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function4(\$arg) {\n return 'function4';\n}", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function5');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function5() { return 'function5'; }", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function6');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function6()\n{\n \$closure = function() { return 'bar'; };\n return 'function6';\n}", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function7');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function7() { return 'function7'; }", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function8');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function8() { return 'function8'; }", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function9');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function9() { return 'function9'; }", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function10');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function10() { \$closure = function() { return 'function10'; }; return \$closure(); }", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function11');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function11() { return 'function11'; }", trim($content));
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function12');
+ $content = $function->getContents(false);
+ $this->assertEquals("function function12() {}", trim($content));
+ }
+
+ public function testFunctionClosureContentsReturnWithoutDocBlock()
+ {
+ require __DIR__ . '/TestAsset/closures.php';
+
+ $function = new FunctionReflection($function2);
+ $content = $function->getContents(false);
+ $this->assertEquals("function() { return 'function2'; }", trim($content));
+
+ $function = new FunctionReflection($function9);
+ $content = $function->getContents(false);
+ $this->assertEquals("function() {}", trim($content));
+
+ $function = new FunctionReflection($function10);
+ $content = $function->getContents(false);
+ $this->assertEquals("function() { return 'function10'; }", trim($content));
+ }
+
+ public function testFunctionContentsReturnWithDocBlock()
+ {
+ require_once __DIR__ . '/TestAsset/functions.php';
+
+ $function = new FunctionReflection('ZendTest\Code\Reflection\TestAsset\function3');
+ $content = $function->getContents();
+ $this->assertEquals("/**\n * Enter description here...\n *\n * @param string \$one\n * @param int \$two"
+ . "\n * @return true\n */\nfunction function3(\$one, \$two = 2)\n{\n return true;\n}", trim($content));
+ }
+
+ public function testFunctionClosureContentsReturnWithDocBlock()
+ {
+ require __DIR__ . '/TestAsset/closures.php';
+
+ $function = new FunctionReflection($function9);
+ $content = $function->getContents();
+ $this->assertEquals("/**\n * closure doc block\n */\nfunction() {}", trim($content));
+ }
}
View
131 tests/ZendTest/Code/Reflection/MethodReflectionTest.php
@@ -43,20 +43,141 @@ public function testStartLine()
$this->assertEquals(21, $reflectionMethod->getStartLine(true));
}
+ public function testInternalFunctionBodyReturn()
+ {
+ $reflectionMethod = new MethodReflection('DOMDocument', 'validate');
+
+ $this->setExpectedException('Zend\Code\Reflection\Exception\InvalidArgumentException');
+ $body = $reflectionMethod->getBody();
+ }
+
public function testGetBodyReturnsCorrectBody()
{
- $body = ' //we need a multi-line method body.
@Ocramius Collaborator

Also here, can you avoid modifying the existing test?

I updated the test because it fail with the function update. There was a bug with \n, so i just add a \n

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ $body = '
+ //we need a multi-line method body.
$assigned = 1;
$alsoAssigined = 2;
- return \'mixedValue\';';
+ return \'mixedValue\';
+ ';
$reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass6', 'doSomething');
$this->assertEquals($body, $reflectionMethod->getBody());
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'doSomething');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "return 'doSomething';");
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'doSomethingElse');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "return 'doSomethingElse';");
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'doSomethingAgain');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "\$closure = function(\$foo) { return \$foo; };\n\n return 'doSomethingAgain';");
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'doStaticSomething');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "return 'doStaticSomething';");
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'inline1');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "return 'inline1';");
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'inline2');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "return 'inline2';");
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'inline3');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "return 'inline3';");
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'emptyFunction');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "");
+
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'visibility');
+ $body = $reflectionMethod->getBody();
+ $this->assertEquals(trim($body), "return 'visibility';");
}
- public function testGetContentsReturnsCorrectContent()
+ public function testInternalMethodContentsReturn()
{
- $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass5', 'doSomething');
- $this->assertEquals(" {\n\n return 'mixedValue';\n\n }\n", $reflectionMethod->getContents(false));
+ $reflectionMethod = new MethodReflection('DOMDocument', 'validate');
+
+ $this->setExpectedException('Zend\Code\Reflection\Exception\InvalidArgumentException');
+ $contents = $reflectionMethod->getContents();
+ }
+
+ public function testMethodContentsReturnWithoutDocBlock()
+ {
+ $contents = <<<CONTENTS
+ public function doSomething()
+ {
+ return 'doSomething';
}
+CONTENTS;
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'doSomething');
+ $this->assertEquals($contents, $reflectionMethod->getContents(false));
+ $contents = ' public function doSomethingElse($one, $two = 2, $three = \'three\') { return \'doSomethingElse\'; }';
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'doSomethingElse');
+ $this->assertEquals($contents, $reflectionMethod->getContents(false));
+
+ $contents = <<<'CONTENTS'
+ public function doSomethingAgain()
+ {
+ $closure = function($foo) { return $foo; };
+
+ return 'doSomethingAgain';
+ }
+CONTENTS;
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'doSomethingAgain');
+ $this->assertEquals($contents, $reflectionMethod->getContents(false));
+
+ $contents = ' public function inline1() { return \'inline1\'; }';
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'inline1');
+ $this->assertEquals($contents, $reflectionMethod->getContents(false));
+
+ $contents = ' public function inline2() { return \'inline2\'; }';
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'inline2');
+ $this->assertEquals($contents, $reflectionMethod->getContents(false));
+
+ $contents = ' public function inline3() { return \'inline3\'; }';
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'inline3');
+ $this->assertEquals($contents, $reflectionMethod->getContents(false));
+
+ $contents = <<<'CONTENTS'
+ public function visibility()
+ {
+ return 'visibility';
+ }
+CONTENTS;
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'visibility');
+ $this->assertEquals($contents, $reflectionMethod->getContents(false));
+ }
+
+ public function testFunctionContentsReturnWithDocBlock()
+ {
+ $contents = <<<'CONTENTS'
+/**
+ * Doc block doSomething
+ * @return string
+ */
+ public function doSomething()
+ {
+ return 'doSomething';
+ }
+CONTENTS;
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'doSomething');
+ $this->assertEquals($contents, $reflectionMethod->getContents(true));
+ $this->assertEquals($contents, $reflectionMethod->getContents());
+
+ $contents = <<<'CONTENTS'
+/**
+ * Awesome doc block
+ */
+ public function emptyFunction() {}
+CONTENTS;
+ $reflectionMethod = new MethodReflection('ZendTest\Code\Reflection\TestAsset\TestSampleClass11', 'emptyFunction');
+ $this->assertEquals($contents, $reflectionMethod->getContents(true));
+ }
}
View
52 tests/ZendTest/Code/Reflection/TestAsset/TestSampleClass11.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace ZendTest\Code\Reflection\TestAsset;
+
+/**
+ * /!\ Don't fix this file with the coding style.
+ * The class Zend\Code\Reflection\FunctionReflection must parse a lot of closure formats
+ */
+class TestSampleClass11
+{
+ /**
+ * Doc block doSomething
+ * @return string
+ */
+ public function doSomething()
+ {
+ return 'doSomething';
+ }
+
+ public function doSomethingElse($one, $two = 2, $three = 'three') { return 'doSomethingElse'; }
+
+ public function doSomethingAgain()
+ {
+ $closure = function($foo) { return $foo; };
+
+ return 'doSomethingAgain';
+ }
+
+ protected static function doStaticSomething()
+ {
+ return 'doStaticSomething';
+ }
+
+ public function inline1() { return 'inline1'; } public function inline2() { return 'inline2'; } public function inline3() { return 'inline3'; }
+
+ /**
+ * Awesome doc block
+ */
+ public function emptyFunction() {}
+
+ public function visibility()
+ {
+ return 'visibility';
+ }
+}
View
47 tests/ZendTest/Code/Reflection/TestAsset/closures.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ */
+
+namespace ZendTest\Code\Reflection\TestAsset;
+
+/***
+ * /!\ Don't fix this file with the coding style.
+ * The class Zend\Code\Reflection\FunctionReflection must parse a lot of closure formats
+ */
+
+$function1 = function()
+{
+ return 'function1';
+};
+
+$function2 = function() { return 'function2'; };
+
+$function3 = function($arg) {
+ return 'function3';
+};
+
+$function4 = function()
+{
+ $closure = function() { return 'bar'; };
+ return 'function4';
+};
+
+$list1 = array('closure' => function() { return 'function5'; });
+
+$list2 = array(function() { return 'function6'; });
+
+$list3 = array(function() { return $c = function() { return 'function7'; }; return $c(); });
+
+$function8 = function() use ($list1) { return 'function 8'; };
+
+/**
+ * closure doc block
+ */
+$function9 = function() {};
+
+eval("\$function10 = function() { return 'function10'; };");
View
30 tests/ZendTest/Code/Reflection/TestAsset/functions.php
@@ -5,14 +5,18 @@
* @link http://github.com/zendframework/zf2 for the canonical source repository
* @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
- * @package Zend_Code
*/
namespace ZendTest\Code\Reflection\TestAsset;
+/***
+ * /!\ Don't fix this file with the coding style.
+ * The class Zend\Code\Reflection\FunctionReflection must parse a lot of closure formats
+ */
+
function function1()
{
- return 'foo';
+ return 'function1';
}
@@ -38,7 +42,27 @@ function function2($one, $two = 'two')
* @param int $two
* @return true
*/
-function function6($one, $two = 2)
+function function3($one, $two = 2)
{
return true;
}
+
+function function4($arg) {
+ return 'function4';
+}
+
+function function5() { return 'function5'; }
+
+function function6()
+{
+ $closure = function() { return 'bar'; };
+ return 'function6';
+}
+
+$foo = 'foo'; function function7() { return 'function7'; }
+
+function function8() { return 'function8'; } function function9() { return 'function9'; }
+
+function function10() { $closure = function() { return 'function10'; }; return $closure(); } function function11() { return 'function11'; }
+
+function function12() {}
Something went wrong with that request. Please try again.