Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] PhpGenerator: Added support for variadics (PHP 5.6 feature) #1414

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 9 additions & 1 deletion Nette/PhpGenerator/Method.php
Expand Up @@ -32,6 +32,8 @@
* @method bool isAbstract()
* @method Method setReturnReference(bool)
* @method bool getReturnReference()
* @method Method setVariadic(bool)
* @method bool isVariadic()
* @method Method setDocuments(string[])
* @method string[] getDocuments()
* @method Method addDocument(string)
Expand Down Expand Up @@ -65,6 +67,9 @@ class Method extends Nette\Object
/** @var bool */
private $returnReference;

/** @var bool */
private $variadic;

/** @var array of string */
private $documents = array();

Expand All @@ -84,6 +89,7 @@ public static function from($from)
$method->abstract = $from->isAbstract() && !$from->getDeclaringClass()->isInterface();
$method->body = $from->isAbstract() ? FALSE : '';
$method->returnReference = $from->returnsReference();
$method->variadic = PHP_VERSION_ID >= 50600 && $from->isVariadic();
$method->documents = preg_replace('#^\s*\* ?#m', '', trim($from->getDocComment(), "/* \r\n"));
return $method;
}
Expand Down Expand Up @@ -129,10 +135,12 @@ public function __toString()
{
$parameters = array();
foreach ($this->parameters as $param) {
$variadic = PHP_VERSION_ID >= 50600 && ($this->variadic || $param->variadic) && count($parameters) === count($this->parameters) - 1;
$parameters[] = ($param->typeHint ? $param->typeHint . ' ' : '')
. ($param->reference ? '&' : '')
. ($variadic ? '...' : '')
. '$' . $param->name
. ($param->optional ? ' = ' . Helpers::dump($param->defaultValue) : '');
. ($param->optional && !$variadic ? ' = ' . Helpers::dump($param->defaultValue) : '');
}
$uses = array();
foreach ($this->uses as $param) {
Expand Down
6 changes: 6 additions & 0 deletions Nette/PhpGenerator/Parameter.php
Expand Up @@ -23,6 +23,8 @@
* @method string getTypeHint()
* @method Parameter setOptional(bool)
* @method bool isOptional()
* @method Parameter setVariadic(bool)
* @method bool isVariadic()
* @method Parameter setDefaultValue(mixed)
* @method mixed getDefaultValue()
*/
Expand All @@ -40,6 +42,9 @@ class Parameter extends Nette\Object
/** @var bool */
private $optional;

/** @var bool */
private $variadic;

/** @var mixed */
public $defaultValue;

Expand All @@ -60,6 +65,7 @@ public static function from(\ReflectionParameter $from)
}
}
$param->optional = PHP_VERSION_ID < 50407 ? $from->isOptional() || ($param->typeHint && $from->allowsNull()) : $from->isDefaultValueAvailable();
$param->variadic = PHP_VERSION_ID >= 50600 && $from->isVariadic();
$param->defaultValue = (PHP_VERSION_ID === 50316 ? $from->isOptional() : $from->isDefaultValueAvailable()) ? $from->getDefaultValue() : NULL;

$namespace = $from->getDeclaringClass()->getNamespaceName();
Expand Down
46 changes: 46 additions & 0 deletions tests/Nette/PhpGenerator/Method.variadics.expect
@@ -0,0 +1,46 @@
function variadic()
{
return 42;
}



function variadic(...$foo)
{
return 42;
}



function variadic($foo, $bar, ...$baz)
{
return 42;
}



function variadic(...$foo)
{
return 42;
}



function variadic($foo, ...$bar)
{
return 42;
}



function variadic(array ...$foo)
{
return 42;
}



function variadic(array &...$foo)
{
return 42;
}
106 changes: 106 additions & 0 deletions tests/Nette/PhpGenerator/Method.variadics.phpt
@@ -0,0 +1,106 @@
<?php

/**
* Test: Nette\PhpGenerator & variadics.
*
* @author Michael Moravec
* @phpversion 5.6
*/

use Nette\PhpGenerator\Method,
Nette\PhpGenerator\Parameter,
Tester\Assert;


require __DIR__ . '/../bootstrap.php';


// test from

interface Variadics
{
function foo(...$foo);
function bar($foo, array &...$bar);
}

$method = Method::from(Variadics::class .'::foo');
Assert::true($method->isVariadic());
Assert::true($method->getParameters()['foo']->isVariadic());

$method = Method::from(Variadics::class . '::bar');
Assert::true($method->isVariadic());
Assert::false($method->getParameters()['foo']->isVariadic());
Assert::true($method->getParameters()['bar']->isVariadic());
Assert::true($method->getParameters()['bar']->isReference());
Assert::same('array', $method->getParameters()['bar']->getTypeHint());



// test generating

$methods = [];


// parameterless variadic method
$methods[] = $method = new Method;
$method->setName('variadic');
$method->setVariadic(TRUE);
$method->setBody('return 42;');


// variadic method with one parameter
$methods[] = $method = new Method;
$method->setName('variadic');
$method->addParameter('foo');
$method->setVariadic(TRUE);
$method->setBody('return 42;');


// variadic method with multiple parameters
$methods[] = $method = new Method;
$method->setName('variadic');
$method->addParameter('foo');
$method->addParameter('bar');
$method->addParameter('baz', []);
$method->setVariadic(TRUE);
$method->setBody('return 42;');


// method with one variadic param
$methods[] = $method = new Method;
$method->setName('variadic');
$method->setParameters([
(new Parameter())->setName('foo')->setVariadic(TRUE)
]);
$method->setBody('return 42;');


// method with more params, last variadic
$methods[] = $method = new Method;
$method->setName('variadic');
$method->setParameters([
(new Parameter())->setName('foo'),
(new Parameter())->setName('bar')->setVariadic(TRUE)
]);
$method->setBody('return 42;');


// method with typehinted variadic param
$methods[] = $method = new Method;
$method->setName('variadic');
$method->setParameters([
(new Parameter())->setName('foo')->setVariadic(TRUE)->setTypeHint('array')
]);
$method->setBody('return 42;');


// method with typrhinted by-value variadic param
$methods[] = $method = new Method;
$method->setName('variadic');
$method->setParameters([
(new Parameter())->setName('foo')->setVariadic(TRUE)->setTypeHint('array')->setReference(TRUE)
]);
$method->setBody('return 42;');


Assert::matchFile(__DIR__ .'/Method.variadics.expect', implode("\n\n\n\n", array_map('strval', $methods)));