BuilderAbstract.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. <?php
  2. namespace PhpParser;
  3. use PhpParser\Comment;
  4. use PhpParser\Node\Expr;
  5. use PhpParser\Node\Name;
  6. use PhpParser\Node\NullableType;
  7. use PhpParser\Node\Scalar;
  8. use PhpParser\Node\Stmt;
  9. abstract class BuilderAbstract implements Builder {
  10. /**
  11. * Normalizes a node: Converts builder objects to nodes.
  12. *
  13. * @param Node|Builder $node The node to normalize
  14. *
  15. * @return Node The normalized node
  16. */
  17. protected function normalizeNode($node) {
  18. if ($node instanceof Builder) {
  19. return $node->getNode();
  20. } elseif ($node instanceof Node) {
  21. return $node;
  22. }
  23. throw new \LogicException('Expected node or builder object');
  24. }
  25. /**
  26. * Normalizes a name: Converts plain string names to PhpParser\Node\Name.
  27. *
  28. * @param Name|string $name The name to normalize
  29. *
  30. * @return Name The normalized name
  31. */
  32. protected function normalizeName($name) {
  33. if ($name instanceof Name) {
  34. return $name;
  35. } elseif (is_string($name)) {
  36. if (!$name) {
  37. throw new \LogicException('Name cannot be empty');
  38. }
  39. if ($name[0] == '\\') {
  40. return new Name\FullyQualified(substr($name, 1));
  41. } elseif (0 === strpos($name, 'namespace\\')) {
  42. return new Name\Relative(substr($name, strlen('namespace\\')));
  43. } else {
  44. return new Name($name);
  45. }
  46. }
  47. throw new \LogicException('Name must be a string or an instance of PhpParser\Node\Name');
  48. }
  49. /**
  50. * Normalizes a type: Converts plain-text type names into proper AST representation.
  51. *
  52. * In particular, builtin types are left as strings, custom types become Names and nullables
  53. * are wrapped in NullableType nodes.
  54. *
  55. * @param Name|string|NullableType $type The type to normalize
  56. *
  57. * @return Name|string|NullableType The normalized type
  58. */
  59. protected function normalizeType($type) {
  60. if (!is_string($type)) {
  61. if (!$type instanceof Name && !$type instanceof NullableType) {
  62. throw new \LogicException(
  63. 'Type must be a string, or an instance of Name or NullableType');
  64. }
  65. return $type;
  66. }
  67. $nullable = false;
  68. if (strlen($type) > 0 && $type[0] === '?') {
  69. $nullable = true;
  70. $type = substr($type, 1);
  71. }
  72. $builtinTypes = array(
  73. 'array', 'callable', 'string', 'int', 'float', 'bool', 'iterable', 'void'
  74. );
  75. $lowerType = strtolower($type);
  76. if (in_array($lowerType, $builtinTypes)) {
  77. $type = $lowerType;
  78. } else {
  79. $type = $this->normalizeName($type);
  80. }
  81. if ($nullable && $type === 'void') {
  82. throw new \LogicException('void type cannot be nullable');
  83. }
  84. return $nullable ? new Node\NullableType($type) : $type;
  85. }
  86. /**
  87. * Normalizes a value: Converts nulls, booleans, integers,
  88. * floats, strings and arrays into their respective nodes
  89. *
  90. * @param mixed $value The value to normalize
  91. *
  92. * @return Expr The normalized value
  93. */
  94. protected function normalizeValue($value) {
  95. if ($value instanceof Node) {
  96. return $value;
  97. } elseif (is_null($value)) {
  98. return new Expr\ConstFetch(
  99. new Name('null')
  100. );
  101. } elseif (is_bool($value)) {
  102. return new Expr\ConstFetch(
  103. new Name($value ? 'true' : 'false')
  104. );
  105. } elseif (is_int($value)) {
  106. return new Scalar\LNumber($value);
  107. } elseif (is_float($value)) {
  108. return new Scalar\DNumber($value);
  109. } elseif (is_string($value)) {
  110. return new Scalar\String_($value);
  111. } elseif (is_array($value)) {
  112. $items = array();
  113. $lastKey = -1;
  114. foreach ($value as $itemKey => $itemValue) {
  115. // for consecutive, numeric keys don't generate keys
  116. if (null !== $lastKey && ++$lastKey === $itemKey) {
  117. $items[] = new Expr\ArrayItem(
  118. $this->normalizeValue($itemValue)
  119. );
  120. } else {
  121. $lastKey = null;
  122. $items[] = new Expr\ArrayItem(
  123. $this->normalizeValue($itemValue),
  124. $this->normalizeValue($itemKey)
  125. );
  126. }
  127. }
  128. return new Expr\Array_($items);
  129. } else {
  130. throw new \LogicException('Invalid value');
  131. }
  132. }
  133. /**
  134. * Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc.
  135. *
  136. * @param Comment\Doc|string $docComment The doc comment to normalize
  137. *
  138. * @return Comment\Doc The normalized doc comment
  139. */
  140. protected function normalizeDocComment($docComment) {
  141. if ($docComment instanceof Comment\Doc) {
  142. return $docComment;
  143. } else if (is_string($docComment)) {
  144. return new Comment\Doc($docComment);
  145. } else {
  146. throw new \LogicException('Doc comment must be a string or an instance of PhpParser\Comment\Doc');
  147. }
  148. }
  149. /**
  150. * Sets a modifier in the $this->type property.
  151. *
  152. * @param int $modifier Modifier to set
  153. */
  154. protected function setModifier($modifier) {
  155. Stmt\Class_::verifyModifier($this->flags, $modifier);
  156. $this->flags |= $modifier;
  157. }
  158. }