GetAttrNode.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\ExpressionLanguage\Node;
  11. use Symfony\Component\ExpressionLanguage\Compiler;
  12. /**
  13. * @author Fabien Potencier <fabien@symfony.com>
  14. *
  15. * @internal
  16. */
  17. class GetAttrNode extends Node
  18. {
  19. const PROPERTY_CALL = 1;
  20. const METHOD_CALL = 2;
  21. const ARRAY_CALL = 3;
  22. public function __construct(Node $node, Node $attribute, ArrayNode $arguments, $type)
  23. {
  24. parent::__construct(
  25. ['node' => $node, 'attribute' => $attribute, 'arguments' => $arguments],
  26. ['type' => $type]
  27. );
  28. }
  29. public function compile(Compiler $compiler)
  30. {
  31. switch ($this->attributes['type']) {
  32. case self::PROPERTY_CALL:
  33. $compiler
  34. ->compile($this->nodes['node'])
  35. ->raw('->')
  36. ->raw($this->nodes['attribute']->attributes['value'])
  37. ;
  38. break;
  39. case self::METHOD_CALL:
  40. $compiler
  41. ->compile($this->nodes['node'])
  42. ->raw('->')
  43. ->raw($this->nodes['attribute']->attributes['value'])
  44. ->raw('(')
  45. ->compile($this->nodes['arguments'])
  46. ->raw(')')
  47. ;
  48. break;
  49. case self::ARRAY_CALL:
  50. $compiler
  51. ->compile($this->nodes['node'])
  52. ->raw('[')
  53. ->compile($this->nodes['attribute'])->raw(']')
  54. ;
  55. break;
  56. }
  57. }
  58. public function evaluate($functions, $values)
  59. {
  60. switch ($this->attributes['type']) {
  61. case self::PROPERTY_CALL:
  62. $obj = $this->nodes['node']->evaluate($functions, $values);
  63. if (!\is_object($obj)) {
  64. throw new \RuntimeException('Unable to get a property on a non-object.');
  65. }
  66. $property = $this->nodes['attribute']->attributes['value'];
  67. return $obj->$property;
  68. case self::METHOD_CALL:
  69. $obj = $this->nodes['node']->evaluate($functions, $values);
  70. if (!\is_object($obj)) {
  71. throw new \RuntimeException('Unable to get a property on a non-object.');
  72. }
  73. if (!\is_callable($toCall = [$obj, $this->nodes['attribute']->attributes['value']])) {
  74. throw new \RuntimeException(sprintf('Unable to call method "%s" of object "%s".', $this->nodes['attribute']->attributes['value'], \get_class($obj)));
  75. }
  76. return \call_user_func_array($toCall, $this->nodes['arguments']->evaluate($functions, $values));
  77. case self::ARRAY_CALL:
  78. $array = $this->nodes['node']->evaluate($functions, $values);
  79. if (!\is_array($array) && !$array instanceof \ArrayAccess) {
  80. throw new \RuntimeException('Unable to get an item on a non-array.');
  81. }
  82. return $array[$this->nodes['attribute']->evaluate($functions, $values)];
  83. }
  84. }
  85. public function toArray()
  86. {
  87. switch ($this->attributes['type']) {
  88. case self::PROPERTY_CALL:
  89. return [$this->nodes['node'], '.', $this->nodes['attribute']];
  90. case self::METHOD_CALL:
  91. return [$this->nodes['node'], '.', $this->nodes['attribute'], '(', $this->nodes['arguments'], ')'];
  92. case self::ARRAY_CALL:
  93. return [$this->nodes['node'], '[', $this->nodes['attribute'], ']'];
  94. }
  95. }
  96. }