1<?php 2 3/* 4 * This file is part of Twig. 5 * 6 * (c) Fabien Potencier 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Twig\Node; 13 14use Twig\Compiler; 15use Twig\Error\SyntaxError; 16 17/** 18 * Represents a macro node. 19 * 20 * @author Fabien Potencier <fabien@symfony.com> 21 */ 22class MacroNode extends Node 23{ 24 const VARARGS_NAME = 'varargs'; 25 26 public function __construct($name, \Twig_NodeInterface $body, \Twig_NodeInterface $arguments, $lineno, $tag = null) 27 { 28 foreach ($arguments as $argumentName => $argument) { 29 if (self::VARARGS_NAME === $argumentName) { 30 throw new SyntaxError(sprintf('The argument "%s" in macro "%s" cannot be defined because the variable "%s" is reserved for arbitrary arguments.', self::VARARGS_NAME, $name, self::VARARGS_NAME), $argument->getTemplateLine(), null, null, false); 31 } 32 } 33 34 parent::__construct(['body' => $body, 'arguments' => $arguments], ['name' => $name], $lineno, $tag); 35 } 36 37 public function compile(Compiler $compiler) 38 { 39 $compiler 40 ->addDebugInfo($this) 41 ->write(sprintf('public function get%s(', $this->getAttribute('name'))) 42 ; 43 44 $count = \count($this->getNode('arguments')); 45 $pos = 0; 46 foreach ($this->getNode('arguments') as $name => $default) { 47 $compiler 48 ->raw('$__'.$name.'__ = ') 49 ->subcompile($default) 50 ; 51 52 if (++$pos < $count) { 53 $compiler->raw(', '); 54 } 55 } 56 57 if (\PHP_VERSION_ID >= 50600) { 58 if ($count) { 59 $compiler->raw(', '); 60 } 61 62 $compiler->raw('...$__varargs__'); 63 } 64 65 $compiler 66 ->raw(")\n") 67 ->write("{\n") 68 ->indent() 69 ; 70 71 $compiler 72 ->write("\$context = \$this->env->mergeGlobals([\n") 73 ->indent() 74 ; 75 76 foreach ($this->getNode('arguments') as $name => $default) { 77 $compiler 78 ->write('') 79 ->string($name) 80 ->raw(' => $__'.$name.'__') 81 ->raw(",\n") 82 ; 83 } 84 85 $compiler 86 ->write('') 87 ->string(self::VARARGS_NAME) 88 ->raw(' => ') 89 ; 90 91 if (\PHP_VERSION_ID >= 50600) { 92 $compiler->raw("\$__varargs__,\n"); 93 } else { 94 $compiler 95 ->raw('func_num_args() > ') 96 ->repr($count) 97 ->raw(' ? array_slice(func_get_args(), ') 98 ->repr($count) 99 ->raw(") : [],\n") 100 ; 101 } 102 103 $compiler 104 ->outdent() 105 ->write("]);\n\n") 106 ->write("\$blocks = [];\n\n") 107 ->write("ob_start();\n") 108 ->write("try {\n") 109 ->indent() 110 ->subcompile($this->getNode('body')) 111 ->outdent() 112 ->write("} catch (\Exception \$e) {\n") 113 ->indent() 114 ->write("ob_end_clean();\n\n") 115 ->write("throw \$e;\n") 116 ->outdent() 117 ->write("} catch (\Throwable \$e) {\n") 118 ->indent() 119 ->write("ob_end_clean();\n\n") 120 ->write("throw \$e;\n") 121 ->outdent() 122 ->write("}\n\n") 123 ->write("return ('' === \$tmp = ob_get_clean()) ? '' : new Markup(\$tmp, \$this->env->getCharset());\n") 124 ->outdent() 125 ->write("}\n\n") 126 ; 127 } 128} 129 130class_alias('Twig\Node\MacroNode', 'Twig_Node_Macro'); 131