1<?php
2
3/*
4 * This file is part of Twig.
5 *
6 * (c) Fabien Potencier
7 * (c) Armin Ronacher
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13namespace Twig\Node\Expression;
14
15use Twig\Compiler;
16use Twig\Extension\SandboxExtension;
17use Twig\Template;
18
19class GetAttrExpression extends AbstractExpression
20{
21    public function __construct(AbstractExpression $node, AbstractExpression $attribute, ?AbstractExpression $arguments, string $type, int $lineno)
22    {
23        $nodes = ['node' => $node, 'attribute' => $attribute];
24        if (null !== $arguments) {
25            $nodes['arguments'] = $arguments;
26        }
27
28        parent::__construct($nodes, ['type' => $type, 'is_defined_test' => false, 'ignore_strict_check' => false, 'optimizable' => true], $lineno);
29    }
30
31    public function compile(Compiler $compiler)
32    {
33        $env = $compiler->getEnvironment();
34
35        // optimize array calls
36        if (
37            $this->getAttribute('optimizable')
38            && (!$env->isStrictVariables() || $this->getAttribute('ignore_strict_check'))
39            && !$this->getAttribute('is_defined_test')
40            && Template::ARRAY_CALL === $this->getAttribute('type')
41        ) {
42            $var = '$'.$compiler->getVarName();
43            $compiler
44                ->raw('(('.$var.' = ')
45                ->subcompile($this->getNode('node'))
46                ->raw(') && is_array(')
47                ->raw($var)
48                ->raw(') || ')
49                ->raw($var)
50                ->raw(' instanceof ArrayAccess ? (')
51                ->raw($var)
52                ->raw('[')
53                ->subcompile($this->getNode('attribute'))
54                ->raw('] ?? null) : null)')
55            ;
56
57            return;
58        }
59
60        $compiler->raw('twig_get_attribute($this->env, $this->source, ');
61
62        if ($this->getAttribute('ignore_strict_check')) {
63            $this->getNode('node')->setAttribute('ignore_strict_check', true);
64        }
65
66        $compiler
67            ->subcompile($this->getNode('node'))
68            ->raw(', ')
69            ->subcompile($this->getNode('attribute'))
70        ;
71
72        if ($this->hasNode('arguments')) {
73            $compiler->raw(', ')->subcompile($this->getNode('arguments'));
74        } else {
75            $compiler->raw(', []');
76        }
77
78        $compiler->raw(', ')
79            ->repr($this->getAttribute('type'))
80            ->raw(', ')->repr($this->getAttribute('is_defined_test'))
81            ->raw(', ')->repr($this->getAttribute('ignore_strict_check'))
82            ->raw(', ')->repr($env->hasExtension(SandboxExtension::class))
83            ->raw(', ')->repr($this->getNode('node')->getTemplateLine())
84            ->raw(')')
85        ;
86    }
87}
88
89class_alias('Twig\Node\Expression\GetAttrExpression', 'Twig_Node_Expression_GetAttr');
90