17 $closingParenthesis =
false;
19 if (is_string($callable) &&
false === strpos($callable,
'::')) {
20 $compiler->
raw($callable);
25 $compiler->
raw(sprintf(
'%s::%s', $callable[0], $callable[1]));
27 $compiler->
raw(sprintf(
'$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1]));
30 $compiler->
raw(sprintf(
'$this->env->getExtension(\'%s\')->%s', get_class($callable[0]), $callable[1]));
33 $compiler->
raw(sprintf(
'call_user_func_array($this->env->get%s(\'%s\')->getCallable(), array',
$type, $this->
getAttribute(
'name')));
34 $closingParenthesis =
true;
43 if ($closingParenthesis) {
55 $compiler->
raw(
'$this->env');
63 $compiler->
raw(
'$context');
68 foreach ($this->
getAttribute(
'arguments') as $argument) {
72 $compiler->
string($argument);
85 if ($this->
hasNode(
'arguments')) {
90 foreach ($arguments as $node) {
107 $parameters = array();
109 foreach ($arguments as
$name => $node) {
110 if (!is_int(
$name)) {
114 throw new Twig_Error_Syntax(sprintf(
'Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName));
117 $parameters[
$name] = $node;
121 if (!$named && !$isVariadic) {
127 $message = sprintf(
'Named arguments are not supported for %s "%s".', $callType, $callName);
129 $message = sprintf(
'Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName);
136 $arguments = array();
138 $missingArguments = array();
139 $optionalArguments = array();
141 foreach ($callableParameters as $callableParameter) {
144 if (array_key_exists(
$name, $parameters)) {
145 if (array_key_exists($pos, $parameters)) {
146 throw new Twig_Error_Syntax(sprintf(
'Argument "%s" is defined twice for %s "%s".',
$name, $callType, $callName));
149 if (
count($missingArguments)) {
151 'Argument "%s" could not be assigned for %s "%s(%s)" because it is mapped to an internal PHP function which cannot determine default value for optional argument%s "%s".',
152 $name, $callType, $callName, implode(
', ', $names),
count($missingArguments) > 1 ?
's' :
'', implode(
'", "', $missingArguments))
156 $arguments = array_merge($arguments, $optionalArguments);
157 $arguments[] = $parameters[
$name];
158 unset($parameters[
$name]);
159 $optionalArguments = array();
160 } elseif (array_key_exists($pos, $parameters)) {
161 $arguments = array_merge($arguments, $optionalArguments);
162 $arguments[] = $parameters[$pos];
163 unset($parameters[$pos]);
164 $optionalArguments = array();
166 } elseif ($callableParameter->isDefaultValueAvailable()) {
168 } elseif ($callableParameter->isOptional()) {
169 if (empty($parameters)) {
172 $missingArguments[] =
$name;
175 throw new Twig_Error_Syntax(sprintf(
'Value for argument "%s" is required for %s "%s".',
$name, $callType, $callName));
181 foreach ($parameters as
$key => $value) {
183 $arbitraryArguments->addElement($value);
187 unset($parameters[
$key]);
190 if ($arbitraryArguments->count()) {
191 $arguments = array_merge($arguments, $optionalArguments);
192 $arguments[] = $arbitraryArguments;
196 if (!empty($parameters)) {
197 $unknownParameter = null;
198 foreach ($parameters as $parameter) {
200 $unknownParameter = $parameter;
206 'Unknown argument%s "%s" for %s "%s(%s)".',
207 count($parameters) > 1 ?
's' :
'', implode(
'", "', array_keys($parameters)), $callType, $callName, implode(
', ', $names)
208 ), $unknownParameter ? $unknownParameter->getTemplateLine() : -1);
216 return strtolower(preg_replace(array(
'/([A-Z]+)([A-Z][a-z])/',
'/([a-z\d])([A-Z])/'), array(
'\\1_\\2',
'\\1_\\2'),
$name));
226 $parameters =
$r->getParameters();
228 array_shift($parameters);
231 array_shift($parameters);
234 array_shift($parameters);
237 foreach ($this->
getAttribute(
'arguments') as $argument) {
238 array_shift($parameters);
242 $argument = end($parameters);
243 if ($argument && $argument->isArray() && $argument->isDefaultValueAvailable() && array() === $argument->getDefaultValue()) {
244 array_pop($parameters);
246 $callableName =
$r->name;
248 $callableName =
$r->getDeclaringClass()->name.
'::'.$callableName;
251 throw new LogicException(sprintf(
'The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = array()".', $callableName, $this->
getAttribute(
'type'), $this->
getAttribute(
'name')));
260 if (null !== $this->reflector) {
264 if (is_array($callable)) {
265 if (!method_exists($callable[0], $callable[1])) {
267 return array(null, array());
270 } elseif (is_object($callable) && !$callable instanceof
Closure) {
271 $r =
new ReflectionObject($callable);
272 $r =
$r->getMethod(
'__invoke');
273 $callable = array($callable,
'__invoke');
274 } elseif (is_string($callable) &&
false !== $pos = strpos($callable,
'::')) {
275 $class = substr($callable, 0, $pos);
276 $method = substr($callable, $pos + 2);
277 if (!method_exists($class, $method)) {
279 return array(null, array());
282 $callable = array($class, $method);
284 $r =
new ReflectionFunction($callable);
287 return $this->reflector = array(
$r, $callable);
291 class_alias(
'Twig_Node_Expression_Call',
'Twig\Node\Expression\CallExpression',
false);
raw($string)
Adds a raw string to the compiled code.
Interface implemented by extension classes.
subcompile(Twig_NodeInterface $node, $raw=true)
Represents a node in the AST.
string($value)
Adds a quoted string to the compiled code.
reflectCallable($callable)
compileArguments(Twig_Compiler $compiler)
Exception thrown when a syntax error occurs during lexing or parsing of a template.
Abstract class for all nodes that represents an expression.
catch(Exception $e) $message
compile(Twig_Compiler $compiler)
Compiles the node to PHP.
getCallableParameters($callable, $isVariadic)
compileCallable(Twig_Compiler $compiler)
getArguments($callable, $arguments)