PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/mailpoet/vendor-prefixed/twig/twig/src/Node/Expression/CallExpression.php

https://gitlab.com/remyvianne/krowkaramel
PHP | 264 lines | 262 code | 0 blank | 2 comment | 21 complexity | 55190b50ec14006d278c61cb83682c90 MD5 | raw file
  1. <?php
  2. namespace MailPoetVendor\Twig\Node\Expression;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoetVendor\Twig\Compiler;
  5. use MailPoetVendor\Twig\Error\SyntaxError;
  6. use MailPoetVendor\Twig\Extension\ExtensionInterface;
  7. use MailPoetVendor\Twig\Node\Node;
  8. abstract class CallExpression extends AbstractExpression
  9. {
  10. private $reflector;
  11. protected function compileCallable(Compiler $compiler)
  12. {
  13. $callable = $this->getAttribute('callable');
  14. $closingParenthesis = \false;
  15. $isArray = \false;
  16. if (\is_string($callable) && \false === \strpos($callable, '::')) {
  17. $compiler->raw($callable);
  18. } else {
  19. list($r, $callable) = $this->reflectCallable($callable);
  20. if ($r instanceof \ReflectionMethod && \is_string($callable[0])) {
  21. if ($r->isStatic()) {
  22. $compiler->raw(\sprintf('%s::%s', $callable[0], $callable[1]));
  23. } else {
  24. $compiler->raw(\sprintf('$this->env->getRuntime(\'%s\')->%s', $callable[0], $callable[1]));
  25. }
  26. } elseif ($r instanceof \ReflectionMethod && $callable[0] instanceof ExtensionInterface) {
  27. // For BC/FC with namespaced aliases
  28. $class = (new \ReflectionClass(\get_class($callable[0])))->name;
  29. if (!$compiler->getEnvironment()->hasExtension($class)) {
  30. // Compile a non-optimized call to trigger a \Twig\Error\RuntimeError, which cannot be a compile-time error
  31. $compiler->raw(\sprintf('$this->env->getExtension(\'%s\')', $class));
  32. } else {
  33. $compiler->raw(\sprintf('$this->extensions[\'%s\']', \ltrim($class, '\\')));
  34. }
  35. $compiler->raw(\sprintf('->%s', $callable[1]));
  36. } else {
  37. $closingParenthesis = \true;
  38. $isArray = \true;
  39. $compiler->raw(\sprintf('call_user_func_array($this->env->get%s(\'%s\')->getCallable(), ', \ucfirst($this->getAttribute('type')), $this->getAttribute('name')));
  40. }
  41. }
  42. $this->compileArguments($compiler, $isArray);
  43. if ($closingParenthesis) {
  44. $compiler->raw(')');
  45. }
  46. }
  47. protected function compileArguments(Compiler $compiler, $isArray = \false)
  48. {
  49. $compiler->raw($isArray ? '[' : '(');
  50. $first = \true;
  51. if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
  52. $compiler->raw('$this->env');
  53. $first = \false;
  54. }
  55. if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
  56. if (!$first) {
  57. $compiler->raw(', ');
  58. }
  59. $compiler->raw('$context');
  60. $first = \false;
  61. }
  62. if ($this->hasAttribute('arguments')) {
  63. foreach ($this->getAttribute('arguments') as $argument) {
  64. if (!$first) {
  65. $compiler->raw(', ');
  66. }
  67. $compiler->string($argument);
  68. $first = \false;
  69. }
  70. }
  71. if ($this->hasNode('node')) {
  72. if (!$first) {
  73. $compiler->raw(', ');
  74. }
  75. $compiler->subcompile($this->getNode('node'));
  76. $first = \false;
  77. }
  78. if ($this->hasNode('arguments')) {
  79. $callable = $this->getAttribute('callable');
  80. $arguments = $this->getArguments($callable, $this->getNode('arguments'));
  81. foreach ($arguments as $node) {
  82. if (!$first) {
  83. $compiler->raw(', ');
  84. }
  85. $compiler->subcompile($node);
  86. $first = \false;
  87. }
  88. }
  89. $compiler->raw($isArray ? ']' : ')');
  90. }
  91. protected function getArguments($callable, $arguments)
  92. {
  93. $callType = $this->getAttribute('type');
  94. $callName = $this->getAttribute('name');
  95. $parameters = [];
  96. $named = \false;
  97. foreach ($arguments as $name => $node) {
  98. if (!\is_int($name)) {
  99. $named = \true;
  100. $name = $this->normalizeName($name);
  101. } elseif ($named) {
  102. throw new SyntaxError(\sprintf('Positional arguments cannot be used after named arguments for %s "%s".', $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
  103. }
  104. $parameters[$name] = $node;
  105. }
  106. $isVariadic = $this->hasAttribute('is_variadic') && $this->getAttribute('is_variadic');
  107. if (!$named && !$isVariadic) {
  108. return $parameters;
  109. }
  110. if (!$callable) {
  111. if ($named) {
  112. $message = \sprintf('Named arguments are not supported for %s "%s".', $callType, $callName);
  113. } else {
  114. $message = \sprintf('Arbitrary positional arguments are not supported for %s "%s".', $callType, $callName);
  115. }
  116. throw new \LogicException($message);
  117. }
  118. list($callableParameters, $isPhpVariadic) = $this->getCallableParameters($callable, $isVariadic);
  119. $arguments = [];
  120. $names = [];
  121. $missingArguments = [];
  122. $optionalArguments = [];
  123. $pos = 0;
  124. foreach ($callableParameters as $callableParameter) {
  125. $name = $this->normalizeName($callableParameter->name);
  126. if (\PHP_VERSION_ID >= 80000 && 'range' === $callable) {
  127. if ('start' === $name) {
  128. $name = 'low';
  129. } elseif ('end' === $name) {
  130. $name = 'high';
  131. }
  132. }
  133. $names[] = $name;
  134. if (\array_key_exists($name, $parameters)) {
  135. if (\array_key_exists($pos, $parameters)) {
  136. throw new SyntaxError(\sprintf('Argument "%s" is defined twice for %s "%s".', $name, $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
  137. }
  138. if (\count($missingArguments)) {
  139. throw new SyntaxError(\sprintf('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".', $name, $callType, $callName, \implode(', ', $names), \count($missingArguments) > 1 ? 's' : '', \implode('", "', $missingArguments)), $this->getTemplateLine(), $this->getSourceContext());
  140. }
  141. $arguments = \array_merge($arguments, $optionalArguments);
  142. $arguments[] = $parameters[$name];
  143. unset($parameters[$name]);
  144. $optionalArguments = [];
  145. } elseif (\array_key_exists($pos, $parameters)) {
  146. $arguments = \array_merge($arguments, $optionalArguments);
  147. $arguments[] = $parameters[$pos];
  148. unset($parameters[$pos]);
  149. $optionalArguments = [];
  150. ++$pos;
  151. } elseif ($callableParameter->isDefaultValueAvailable()) {
  152. $optionalArguments[] = new ConstantExpression($callableParameter->getDefaultValue(), -1);
  153. } elseif ($callableParameter->isOptional()) {
  154. if (empty($parameters)) {
  155. break;
  156. } else {
  157. $missingArguments[] = $name;
  158. }
  159. } else {
  160. throw new SyntaxError(\sprintf('Value for argument "%s" is required for %s "%s".', $name, $callType, $callName), $this->getTemplateLine(), $this->getSourceContext());
  161. }
  162. }
  163. if ($isVariadic) {
  164. $arbitraryArguments = $isPhpVariadic ? new VariadicExpression([], -1) : new ArrayExpression([], -1);
  165. foreach ($parameters as $key => $value) {
  166. if (\is_int($key)) {
  167. $arbitraryArguments->addElement($value);
  168. } else {
  169. $arbitraryArguments->addElement($value, new ConstantExpression($key, -1));
  170. }
  171. unset($parameters[$key]);
  172. }
  173. if ($arbitraryArguments->count()) {
  174. $arguments = \array_merge($arguments, $optionalArguments);
  175. $arguments[] = $arbitraryArguments;
  176. }
  177. }
  178. if (!empty($parameters)) {
  179. $unknownParameter = null;
  180. foreach ($parameters as $parameter) {
  181. if ($parameter instanceof Node) {
  182. $unknownParameter = $parameter;
  183. break;
  184. }
  185. }
  186. throw new SyntaxError(\sprintf('Unknown argument%s "%s" for %s "%s(%s)".', \count($parameters) > 1 ? 's' : '', \implode('", "', \array_keys($parameters)), $callType, $callName, \implode(', ', $names)), $unknownParameter ? $unknownParameter->getTemplateLine() : $this->getTemplateLine(), $unknownParameter ? $unknownParameter->getSourceContext() : $this->getSourceContext());
  187. }
  188. return $arguments;
  189. }
  190. protected function normalizeName($name)
  191. {
  192. return \strtolower(\preg_replace(['/([A-Z]+)([A-Z][a-z])/', '/([a-z\\d])([A-Z])/'], ['\\1_\\2', '\\1_\\2'], $name));
  193. }
  194. private function getCallableParameters($callable, bool $isVariadic) : array
  195. {
  196. list($r) = $this->reflectCallable($callable);
  197. if (null === $r) {
  198. return [[], \false];
  199. }
  200. $parameters = $r->getParameters();
  201. if ($this->hasNode('node')) {
  202. \array_shift($parameters);
  203. }
  204. if ($this->hasAttribute('needs_environment') && $this->getAttribute('needs_environment')) {
  205. \array_shift($parameters);
  206. }
  207. if ($this->hasAttribute('needs_context') && $this->getAttribute('needs_context')) {
  208. \array_shift($parameters);
  209. }
  210. if ($this->hasAttribute('arguments') && null !== $this->getAttribute('arguments')) {
  211. foreach ($this->getAttribute('arguments') as $argument) {
  212. \array_shift($parameters);
  213. }
  214. }
  215. $isPhpVariadic = \false;
  216. if ($isVariadic) {
  217. $argument = \end($parameters);
  218. $isArray = $argument && $argument->hasType() && 'array' === $argument->getType()->getName();
  219. if ($isArray && $argument->isDefaultValueAvailable() && [] === $argument->getDefaultValue()) {
  220. \array_pop($parameters);
  221. } elseif ($argument && $argument->isVariadic()) {
  222. \array_pop($parameters);
  223. $isPhpVariadic = \true;
  224. } else {
  225. $callableName = $r->name;
  226. if ($r instanceof \ReflectionMethod) {
  227. $callableName = $r->getDeclaringClass()->name . '::' . $callableName;
  228. }
  229. throw new \LogicException(\sprintf('The last parameter of "%s" for %s "%s" must be an array with default value, eg. "array $arg = []".', $callableName, $this->getAttribute('type'), $this->getAttribute('name')));
  230. }
  231. }
  232. return [$parameters, $isPhpVariadic];
  233. }
  234. private function reflectCallable($callable)
  235. {
  236. if (null !== $this->reflector) {
  237. return $this->reflector;
  238. }
  239. if (\is_array($callable)) {
  240. if (!\method_exists($callable[0], $callable[1])) {
  241. // __call()
  242. return [null, []];
  243. }
  244. $r = new \ReflectionMethod($callable[0], $callable[1]);
  245. } elseif (\is_object($callable) && !$callable instanceof \Closure) {
  246. $r = new \ReflectionObject($callable);
  247. $r = $r->getMethod('__invoke');
  248. $callable = [$callable, '__invoke'];
  249. } elseif (\is_string($callable) && \false !== ($pos = \strpos($callable, '::'))) {
  250. $class = \substr($callable, 0, $pos);
  251. $method = \substr($callable, $pos + 2);
  252. if (!\method_exists($class, $method)) {
  253. // __staticCall()
  254. return [null, []];
  255. }
  256. $r = new \ReflectionMethod($callable);
  257. $callable = [$class, $method];
  258. } else {
  259. $r = new \ReflectionFunction($callable);
  260. }
  261. return $this->reflector = [$r, $callable];
  262. }
  263. }
  264. \class_alias('MailPoetVendor\\Twig\\Node\\Expression\\CallExpression', 'MailPoetVendor\\Twig_Node_Expression_Call');