diff --git a/CHANGELOG.md b/CHANGELOG.md index 4772c69..9befecd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Isolator Changelog +### 3.0.1 (2014-10-21) + +* **[FIXED]** References are now preserved when calling functions with variable arguments + ### 3.0.0 (2014-10-08) * **[BC]** Removed `Isolator::getIsolator()` and `resetIsolator()` diff --git a/README.md b/README.md index a42179c..49bd51f 100644 --- a/README.md +++ b/README.md @@ -167,8 +167,9 @@ PHP 5.6. * Follow [@IcecaveStudios](https://twitter.com/IcecaveStudios) on Twitter * Visit the [Icecave Studios website](http://icecave.com.au) +* Join `#icecave` on [irc.freenode.net](http://webchat.freenode.net?channels=icecave) [Build Status]: http://img.shields.io/travis/IcecaveStudios/isolator/develop.svg?style=flat-square [Test Coverage]: http://img.shields.io/coveralls/IcecaveStudios/isolator/develop.svg?style=flat-square -[SemVer]: http://img.shields.io/:semver-3.0.0-brightgreen.svg?style=flat-square +[SemVer]: http://img.shields.io/:semver-3.0.1-brightgreen.svg?style=flat-square diff --git a/benchmark/benchmark.php b/benchmark/benchmark.php index a168330..40e2bbf 100755 --- a/benchmark/benchmark.php +++ b/benchmark/benchmark.php @@ -6,6 +6,9 @@ $isolator = Icecave\Isolator\Isolator::get(); +$reflector = new ReflectionClass($isolator); +echo $reflector->getFilename() . PHP_EOL; + class TestClass { public function __construct($param = null) diff --git a/src/Detail/CodeGenerator.php b/src/Detail/CodeGenerator.php index 72bfef8..9dff75a 100644 --- a/src/Detail/CodeGenerator.php +++ b/src/Detail/CodeGenerator.php @@ -42,7 +42,14 @@ public function generate($className, array $functions) $code .= 'class ' . $shortName . ' extends AbstractIsolator' . PHP_EOL; $code .= '{' . PHP_EOL; + $newLine = false; foreach ($functions as $function) { + if ($newLine) { + $code .= PHP_EOL; + } else { + $newLine = true; + } + $code .= $this->generateMethod( new ReflectionFunction($function) ); @@ -70,12 +77,20 @@ private function generateMethod(ReflectionFunction $reflector) $code = ' ' . $signature . PHP_EOL; $code .= ' {' . PHP_EOL; $code .= $this->generateSwitch($name, $minArity, $maxArity); - $code .= ' return \call_user_func_array(' . var_export($reflector->getName(), true) . ', \func_get_args());' . PHP_EOL; + $code .= PHP_EOL; + $code .= $this->generateFallbackReturn($name, $refIndices); $code .= ' }' . PHP_EOL; return $code; } + /** + * @param string $name The function name. + * @param boolean $returnsReference True if the function returns a reference. + * @param integer $minArity The minimum number of arguments. + * @param integer $maxArity The maximum number of arguments present in the signature. + * @param array $refIndices An array containing the indices of parameters that are references. + */ private function generateSignature( $name, $returnsReference, @@ -138,6 +153,22 @@ private function generateReturn($name, $arity) ); } + public function generateFallbackReturn($name, $refIndices) + { + $code = ' $arguments = \func_get_args();' . PHP_EOL; + + foreach ($refIndices as $index => $isReference) { + if ($isReference) { + $code .= ' $arguments[' . $index . '] = &$p' . $index . ';' . PHP_EOL; + } + } + + $code .= PHP_EOL; + $code .= ' return \call_user_func_array(' . var_export($name, true) . ', $arguments);' . PHP_EOL; + + return $code; + } + private function inspectParameters(ReflectionFunction $reflector) { $minArity = 0; diff --git a/src/PackageInfo.php b/src/PackageInfo.php index 45ce146..c1a8016 100644 --- a/src/PackageInfo.php +++ b/src/PackageInfo.php @@ -4,5 +4,5 @@ class PackageInfo { const NAME = 'Isolator'; - const VERSION = '3.0.0'; + const VERSION = '3.0.1'; } diff --git a/test/suite/Detail/CodeGeneratorTest.php b/test/suite/Detail/CodeGeneratorTest.php index ea80565..c4dd668 100644 --- a/test/suite/Detail/CodeGeneratorTest.php +++ b/test/suite/Detail/CodeGeneratorTest.php @@ -71,7 +71,10 @@ public function testGenerateMethod() $expectedCode .= ' switch (\func_num_args()) {' . PHP_EOL; $expectedCode .= ' case 1: return \strlen($p0);' . PHP_EOL; $expectedCode .= ' }' . PHP_EOL; - $expectedCode .= ' return \call_user_func_array(\'strlen\', \func_get_args());' . PHP_EOL; + $expectedCode .= PHP_EOL; + $expectedCode .= ' $arguments = \func_get_args();' . PHP_EOL; + $expectedCode .= PHP_EOL; + $expectedCode .= ' return \call_user_func_array(\'strlen\', $arguments);' . PHP_EOL; $expectedCode .= ' }' . PHP_EOL; $expectedCode .= '}' . PHP_EOL; @@ -100,7 +103,11 @@ public function testGenerateMethodWithReferenceParameter() $expectedCode .= ' case 2: return \ereg($p0, $p1);' . PHP_EOL; $expectedCode .= ' case 3: return \ereg($p0, $p1, $p2);' . PHP_EOL; $expectedCode .= ' }' . PHP_EOL; - $expectedCode .= ' return \call_user_func_array(\'ereg\', \func_get_args());' . PHP_EOL; + $expectedCode .= PHP_EOL; + $expectedCode .= ' $arguments = \func_get_args();' . PHP_EOL; + $expectedCode .= ' $arguments[2] = &$p2;' . PHP_EOL; + $expectedCode .= PHP_EOL; + $expectedCode .= ' return \call_user_func_array(\'ereg\', $arguments);' . PHP_EOL; $expectedCode .= ' }' . PHP_EOL; $expectedCode .= '}' . PHP_EOL; @@ -128,7 +135,10 @@ public function testGenerateMethodWithVarArgs() $expectedCode .= ' switch (\func_num_args()) {' . PHP_EOL; $expectedCode .= ' case 2: return \sprintf($p0, $p1);' . PHP_EOL; $expectedCode .= ' }' . PHP_EOL; - $expectedCode .= ' return \call_user_func_array(\'sprintf\', \func_get_args());' . PHP_EOL; + $expectedCode .= PHP_EOL; + $expectedCode .= ' $arguments = \func_get_args();' . PHP_EOL; + $expectedCode .= PHP_EOL; + $expectedCode .= ' return \call_user_func_array(\'sprintf\', $arguments);' . PHP_EOL; $expectedCode .= ' }' . PHP_EOL; $expectedCode .= '}' . PHP_EOL; diff --git a/test/suite/IsolatorTest.php b/test/suite/IsolatorTest.php index fde13c1..9f0e3dd 100644 --- a/test/suite/IsolatorTest.php +++ b/test/suite/IsolatorTest.php @@ -195,4 +195,20 @@ public function testGet() Isolator::get() ); } + + /** + * @group regression + * @link https://github.com/IcecaveStudios/isolator/issues/17 + */ + public function testCallVarArgsWithReferences() + { + $array = array(); + + $this->isolator->array_push($array, 1, 2); + + $this->assertSame( + array(1, 2), + $array + ); + } }