Overview

Namespaces

  • Pharborist
    • Constants
    • ControlStructures
    • Exceptions
    • Functions
    • Generators
    • Namespaces
    • Objects
    • Operators
    • Types
    • Variables

Classes

  • Pharborist\Variables\CompoundVariableNode
  • Pharborist\Variables\GlobalStatementNode
  • Pharborist\Variables\ReferenceVariableNode
  • Pharborist\Variables\StaticVariableNode
  • Pharborist\Variables\StaticVariableStatementNode
  • Pharborist\Variables\VariableNode
  • Pharborist\Variables\VariableVariableNode

Interfaces

  • Pharborist\Variables\VariableExpressionNode
  • Overview
  • Namespace
  • Class
  1: <?php
  2: namespace Pharborist;
  3: 
  4: use Pharborist\Types\ArrayNode;
  5: 
  6: /**
  7:  * Any comma-separated set of nodes. This includes class member lists, function
  8:  * call arguments, array elements, etc.
  9:  */
 10: class CommaListNode extends ParentNode {
 11:   /**
 12:    * @return NodeCollection
 13:    */
 14:   public function getItems() {
 15:     $items = [];
 16:     $child = $this->head;
 17:     while ($child) {
 18:       if ($child instanceof HiddenNode) {
 19:         // ignore hidden nodes
 20:       }
 21:       elseif ($child instanceof TokenNode && $child->getType() === ',') {
 22:         // ignore comma
 23:       }
 24:       else {
 25:         $items[] = $child;
 26:       }
 27:       $child = $child->next;
 28:     }
 29:     return new NodeCollection($items, FALSE);
 30:   }
 31: 
 32:   /**
 33:    * @param int $index
 34:    * @throws \OutOfBoundsException
 35:    *   Index is out of bounds.
 36:    * @return Node
 37:    */
 38:   public function getItem($index) {
 39:     if ($index < 0) {
 40:       throw new \OutOfBoundsException('Index is out of bounds');
 41:     }
 42:     $i = 0;
 43:     $child = $this->head;
 44:     while ($child) {
 45:       if ($child instanceof HiddenNode) {
 46:         // ignore hidden nodes
 47:       }
 48:       elseif ($child instanceof TokenNode && $child->getType() === ',') {
 49:         // ignore comma
 50:       }
 51:       else {
 52:         if ($i === $index) {
 53:           return $child;
 54:         }
 55:         $i++;
 56:       }
 57:       $child = $child->next;
 58:     }
 59:     throw new \OutOfBoundsException('Index is out of bounds');
 60:   }
 61: 
 62:   /**
 63:    * Prepend item.
 64:    *
 65:    * @param Node $item
 66:    * @return $this
 67:    */
 68:   public function prependItem(Node $item) {
 69:     if ($this->getItems()->isEmpty()) {
 70:       $this->append($item);
 71:     }
 72:     else {
 73:       $this->prepend([
 74:         $item,
 75:         Token::comma(),
 76:         Token::space(),
 77:       ]);
 78:     }
 79:     return $this;
 80:   }
 81: 
 82:   /**
 83:    * Append item.
 84:    *
 85:    * @param Node $item
 86:    * @return $this
 87:    */
 88:   public function appendItem(Node $item) {
 89:     if ($this->getItems()->isEmpty()) {
 90:       $this->append($item);
 91:     }
 92:     else {
 93:       $this->append([
 94:         Token::comma(),
 95:         Token::space(),
 96:         $item,
 97:       ]);
 98:     }
 99:     return $this;
100:   }
101: 
102:   /**
103:    * Insert item before index.
104:    *
105:    * @param Node $item
106:    * @param int $index
107:    * @throws \OutOfBoundsException
108:    *   Index out of bounds.
109:    * @return $this
110:    */
111:   public function insertItem(Node $item, $index) {
112:     $items = $this->getItems();
113:     if ($items->isEmpty()) {
114:       if ($index !== 0) {
115:         throw new \OutOfBoundsException('index out of bounds');
116:       }
117:       $this->append($item);
118:     }
119:     else {
120:       $max_index = count($items) - 1;
121:       if ($index < 0 || $index > $max_index) {
122:         throw new \OutOfBoundsException('index out of bounds');
123:       }
124:       $items[$index]->before([
125:         $item,
126:         Token::comma(),
127:         Token::space(),
128:       ]);
129:     }
130:     return $this;
131:   }
132: 
133:   /**
134:    * Remove item.
135:    *
136:    * @param int|Node $item
137:    *   The index of item or item to remove.
138:    * @throws \OutOfBoundsException
139:    *   Index out of bounds.
140:    * @throws \InvalidArgumentException
141:    *   Item does not exist in list.
142:    * @return $this
143:    */
144:   public function removeItem($item) {
145:     if (is_int($item)) {
146:       $index = $item;
147:       if ($index < 0) {
148:         throw new \OutOfBoundsException('index out of bounds');
149:       }
150:       $items = $this->getItems();
151:       if ($index >= count($items)) {
152:         throw new \OutOfBoundsException('index out of bounds');
153:       }
154:       $item = $items[$index];
155:       $is_last = $index === count($items) - 1;
156:     }
157:     else {
158:       if ($item->parent() !== $this) {
159:         throw new \InvalidArgumentException('invalid item');
160:       }
161:       $items = $this->getItems();
162:       $last_index = count($items) - 1;
163:       $last_item = $items[$last_index];
164:       $is_last = $last_item === $item;
165:     }
166:     if (count($items) === 1) {
167:       // No separators to remove.
168:     }
169:     elseif ($is_last) {
170:       $item->previousUntil(function ($node) {
171:         if ($node instanceof HiddenNode) {
172:           return FALSE;
173:         }
174:         if ($node instanceof TokenNode && $node->getType() === ',') {
175:           return FALSE;
176:         }
177:         return TRUE;
178:       })->remove();
179:     }
180:     else {
181:       $item->nextUntil(function ($node) {
182:         if ($node instanceof HiddenNode) {
183:           return FALSE;
184:         }
185:         if ($node instanceof TokenNode && $node->getType() === ',') {
186:           return FALSE;
187:         }
188:         return TRUE;
189:       })->remove();
190:     }
191:     $item->remove();
192:     return $this;
193:   }
194: 
195:   /**
196:    * Pop an item off end of the list.
197:    *
198:    * @return Node
199:    *   The removed item. NULL if item list is empty.
200:    */
201:   public function pop() {
202:     $items = $this->getItems();
203:     if ($items->isEmpty()) {
204:       return NULL;
205:     }
206:     if (count($items) === 1) {
207:       $pop_item = $items[0];
208:       $pop_item->remove();
209:       return $pop_item;
210:     }
211:     $pop_item = $items[count($items) - 1];
212:     $pop_item->previousUntil(function ($node) {
213:       if ($node instanceof HiddenNode) {
214:         return FALSE;
215:       }
216:       if ($node instanceof TokenNode && $node->getType() === ',') {
217:         return FALSE;
218:       }
219:       return TRUE;
220:     })->remove();
221:     $pop_item->remove();
222:     return $pop_item;
223:   }
224: 
225:   /**
226:    * Shift an item off start of the list.
227:    *
228:    * @return Node
229:    *   The removed item. NULL if item list is empty.
230:    */
231:   public function shift() {
232:     $items = $this->getItems();
233:     if ($items->isEmpty()) {
234:       return NULL;
235:     }
236:     if (count($items) === 1) {
237:       $pop_item = $items[0];
238:       $pop_item->remove();
239:       return $pop_item;
240:     }
241:     $pop_item = $items[0];
242:     $pop_item->nextUntil(function ($node) {
243:       if ($node instanceof HiddenNode) {
244:         return FALSE;
245:       }
246:       if ($node instanceof TokenNode && $node->getType() === ',') {
247:         return FALSE;
248:       }
249:       return TRUE;
250:     })->remove();
251:     $pop_item->remove();
252:     return $pop_item;
253:   }
254: 
255:   /**
256:    * Returns this comma list as an ArrayNode.
257:    *
258:    * @return ArrayNode
259:    */
260:   public function toArrayNode() {
261:     return ($this->parent instanceof ArrayNode) ? clone $this->parent : Parser::parseExpression('[' . $this->getText() . ']');
262:   }
263: }
264: 
Pharborist API documentation generated by ApiGen