Overview

Namespaces

  • TokenReflection
    • Broker
      • Backend
    • Dummy
    • Exception
    • Invalid
    • Php
    • Stream

Classes

  • Broker
  • ReflectionAnnotation
  • ReflectionBase
  • ReflectionClass
  • ReflectionConstant
  • ReflectionElement
  • ReflectionFile
  • ReflectionFileNamespace
  • ReflectionFunction
  • ReflectionFunctionBase
  • ReflectionMethod
  • ReflectionNamespace
  • ReflectionParameter
  • ReflectionProperty
  • Resolver

Interfaces

  • IReflection
  • IReflectionClass
  • IReflectionConstant
  • IReflectionExtension
  • IReflectionFunction
  • IReflectionFunctionBase
  • IReflectionMethod
  • IReflectionNamespace
  • IReflectionParameter
  • IReflectionProperty
  • Overview
  • Namespace
  • Class
  • Tree
  • Download
  1: <?php
  2: /**
  3:  * PHP Token Reflection
  4:  *
  5:  * Version 1.3.1
  6:  *
  7:  * LICENSE
  8:  *
  9:  * This source file is subject to the new BSD license that is bundled
 10:  * with this library in the file LICENSE.
 11:  *
 12:  * @author Ondřej Nešpor
 13:  * @author Jaroslav Hanslík
 14:  */
 15: 
 16: namespace TokenReflection;
 17: 
 18: use TokenReflection\Exception, TokenReflection\Stream\StreamBase as Stream;
 19: 
 20: /**
 21:  * Reflection of a namespace parsed from a file.
 22:  */
 23: class ReflectionFileNamespace extends ReflectionElement
 24: {
 25:     /**
 26:      * List of class reflections.
 27:      *
 28:      * @var array
 29:      */
 30:     private $classes = array();
 31: 
 32:     /**
 33:      * List of constant reflections.
 34:      *
 35:      * @var array
 36:      */
 37:     private $constants = array();
 38: 
 39:     /**
 40:      * List of function reflections.
 41:      *
 42:      * @var array
 43:      */
 44:     private $functions = array();
 45: 
 46:     /**
 47:      * Namespace aliases.
 48:      *
 49:      * @var array
 50:      */
 51:     private $aliases = array();
 52: 
 53:     /**
 54:      * Returns class reflections.
 55:      *
 56:      * @return array
 57:      */
 58:     public function getClasses()
 59:     {
 60:         return $this->classes;
 61:     }
 62: 
 63:     /**
 64:      * Returns constant reflections.
 65:      *
 66:      * @return array
 67:      */
 68:     public function getConstants()
 69:     {
 70:         return $this->constants;
 71:     }
 72: 
 73:     /**
 74:      * Returns function reflections.
 75:      *
 76:      * @return array
 77:      */
 78:     public function getFunctions()
 79:     {
 80:         return $this->functions;
 81:     }
 82: 
 83:     /**
 84:      * Returns all imported namespaces and aliases.
 85:      *
 86:      * @return array
 87:      */
 88:     public function getNamespaceAliases()
 89:     {
 90:         return $this->aliases;
 91:     }
 92: 
 93:     /**
 94:      * Processes the parent reflection object.
 95:      *
 96:      * @param \TokenReflection\IReflection $parent Parent reflection object
 97:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
 98:      * @return \TokenReflection\ReflectionElement
 99:      * @throws \TokenReflection\Exception\ParseException If an invalid parent reflection object was provided.
100:      */
101:     protected function processParent(IReflection $parent, Stream $tokenStream)
102:     {
103:         if (!$parent instanceof ReflectionFile) {
104:             throw new Exception\ParseException($this, $tokenStream, 'The parent object has to be an instance of TokenReflection\ReflectionFile.', Exception\ParseException::INVALID_PARENT);
105:         }
106: 
107:         return parent::processParent($parent, $tokenStream);
108:     }
109: 
110:     /**
111:      * Parses reflected element metadata from the token stream.
112:      *
113:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
114:      * @param \TokenReflection\IReflection $parent Parent reflection object
115:      * @return \TokenReflection\ReflectionFileNamespace
116:      */
117:     protected function parse(Stream $tokenStream, IReflection $parent)
118:     {
119:         return $this->parseName($tokenStream);
120:     }
121: 
122:     /**
123:      * Find the appropriate docblock.
124:      *
125:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
126:      * @param \TokenReflection\IReflection $parent Parent reflection
127:      * @return \TokenReflection\ReflectionElement
128:      */
129:     protected function parseDocComment(Stream $tokenStream, IReflection $parent)
130:     {
131:         if (!$tokenStream->is(T_NAMESPACE)) {
132:             $this->docComment = new ReflectionAnnotation($this);
133:             return $this;
134:         } else {
135:             return parent::parseDocComment($tokenStream, $parent);
136:         }
137:     }
138: 
139:     /**
140:      * Parses the namespace name.
141:      *
142:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
143:      * @return \TokenReflection\ReflectionFileNamespace
144:      * @throws \TokenReflection\Exception\ParseException If the namespace name could not be determined.
145:      */
146:     protected function parseName(Stream $tokenStream)
147:     {
148:         if (!$tokenStream->is(T_NAMESPACE)) {
149:             $this->name = ReflectionNamespace::NO_NAMESPACE_NAME;
150:             return $this;
151:         }
152: 
153:         $tokenStream->skipWhitespaces();
154: 
155:         $name = '';
156:         // Iterate over the token stream
157:         while (true) {
158:             switch ($tokenStream->getType()) {
159:                 // If the current token is a T_STRING, it is a part of the namespace name
160:                 case T_STRING:
161:                 case T_NS_SEPARATOR:
162:                     $name .= $tokenStream->getTokenValue();
163:                     break;
164:                 default:
165:                     // Stop iterating when other token than string or ns separator found
166:                     break 2;
167:             }
168: 
169:             $tokenStream->skipWhitespaces(true);
170:         }
171: 
172:         $name = ltrim($name, '\\');
173: 
174:         if (empty($name)) {
175:             $this->name = ReflectionNamespace::NO_NAMESPACE_NAME;
176:         } else {
177:             $this->name = $name;
178:         }
179: 
180:         if (!$tokenStream->is(';') && !$tokenStream->is('{')) {
181:             throw new Exception\ParseException($this, $tokenStream, 'Invalid namespace name end, expecting ";" or "{".', Exception\ParseException::UNEXPECTED_TOKEN);
182:         }
183: 
184:         $tokenStream->skipWhitespaces();
185: 
186:         return $this;
187:     }
188: 
189:     /**
190:      * Parses child reflection objects from the token stream.
191:      *
192:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
193:      * @param \TokenReflection\IReflection $parent Parent reflection object
194:      * @return \TokenReflection\ReflectionFileNamespace
195:      * @throws \TokenReflection\Exception\ParseException If child elements could not be parsed.
196:      */
197:     protected function parseChildren(Stream $tokenStream, IReflection $parent)
198:     {
199:         static $skipped = array(T_WHITESPACE => true, T_COMMENT => true, T_DOC_COMMENT => true);
200:         $depth = 0;
201: 
202:         $firstChild = null;
203: 
204:         while (true) {
205:             switch ($tokenStream->getType()) {
206:                 case T_USE:
207:                     while (true) {
208:                         $namespaceName = '';
209:                         $alias = null;
210: 
211:                         $tokenStream->skipWhitespaces(true);
212: 
213:                         while (true) {
214:                             switch ($tokenStream->getType()) {
215:                                 case T_STRING:
216:                                 case T_NS_SEPARATOR:
217:                                     $namespaceName .= $tokenStream->getTokenValue();
218:                                     break;
219:                                 default:
220:                                     break 2;
221:                             }
222:                             $tokenStream->skipWhitespaces(true);
223:                         }
224:                         $namespaceName = ltrim($namespaceName, '\\');
225: 
226:                         if (empty($namespaceName)) {
227:                             throw new Exception\ParseException($this, $tokenStream, 'Imported namespace name could not be determined.', Exception\ParseException::LOGICAL_ERROR);
228:                         } elseif ('\\' === substr($namespaceName, -1)) {
229:                             throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid namespace name "%s".', $namespaceName), Exception\ParseException::LOGICAL_ERROR);
230:                         }
231: 
232:                         if ($tokenStream->is(T_AS)) {
233:                             // Alias defined
234:                             $tokenStream->skipWhitespaces(true);
235: 
236:                             if (!$tokenStream->is(T_STRING)) {
237:                                 throw new Exception\ParseException($this, $tokenStream, sprintf('The imported namespace "%s" seems aliased but the alias name could not be determined.', $namespaceName), Exception\ParseException::LOGICAL_ERROR);
238:                             }
239: 
240:                             $alias = $tokenStream->getTokenValue();
241: 
242:                             $tokenStream->skipWhitespaces(true);
243:                         } else {
244:                             // No explicit alias
245:                             if (false !== ($pos = strrpos($namespaceName, '\\'))) {
246:                                 $alias = substr($namespaceName, $pos + 1);
247:                             } else {
248:                                 $alias = $namespaceName;
249:                             }
250:                         }
251: 
252:                         if (isset($this->aliases[$alias])) {
253:                             throw new Exception\ParseException($this, $tokenStream, sprintf('Namespace alias "%s" already defined.', $alias), Exception\ParseException::LOGICAL_ERROR);
254:                         }
255: 
256:                         $this->aliases[$alias] = $namespaceName;
257: 
258:                         $type = $tokenStream->getType();
259:                         if (';' === $type) {
260:                             $tokenStream->skipWhitespaces();
261:                             break 2;
262:                         } elseif (',' === $type) {
263:                             // Next namespace in the current "use" definition
264:                             continue;
265:                         }
266: 
267:                         throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
268:                     }
269: 
270:                 case T_COMMENT:
271:                 case T_DOC_COMMENT:
272:                     $docblock = $tokenStream->getTokenValue();
273:                     if (preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $docblock)) {
274:                         array_unshift($this->docblockTemplates, new ReflectionAnnotation($this, $docblock));
275:                     } elseif (self::DOCBLOCK_TEMPLATE_END === $docblock) {
276:                         array_shift($this->docblockTemplates);
277:                     }
278:                     $tokenStream->next();
279:                     break;
280:                 case '{':
281:                     $tokenStream->next();
282:                     $depth++;
283:                     break;
284:                 case '}':
285:                     if (0 === $depth--) {
286:                         break 2;
287:                     }
288: 
289:                     $tokenStream->next();
290:                     break;
291:                 case null:
292:                 case T_NAMESPACE:
293:                     break 2;
294:                 case T_ABSTRACT:
295:                 case T_FINAL:
296:                 case T_CLASS:
297:                 case T_TRAIT:
298:                 case T_INTERFACE:
299:                     $class = new ReflectionClass($tokenStream, $this->getBroker(), $this);
300:                     $firstChild = $firstChild ?: $class;
301: 
302:                     $className = $class->getName();
303:                     if (isset($this->classes[$className])) {
304:                         if (!$this->classes[$className] instanceof Invalid\ReflectionClass) {
305:                             $this->classes[$className] = new Invalid\ReflectionClass($className, $this->classes[$className]->getFileName(), $this->getBroker());
306:                         }
307: 
308:                         if (!$this->classes[$className]->hasReasons()) {
309:                             $this->classes[$className]->addReason(new Exception\ParseException(
310:                                 $this,
311:                                 $tokenStream,
312:                                 sprintf('Class %s is defined multiple times in the file.', $className),
313:                                 Exception\ParseException::ALREADY_EXISTS
314:                             ));
315:                         }
316:                     } else {
317:                         $this->classes[$className] = $class;
318:                     }
319:                     $tokenStream->next();
320:                     break;
321:                 case T_CONST:
322:                     $tokenStream->skipWhitespaces(true);
323:                     do {
324:                         $constant = new ReflectionConstant($tokenStream, $this->getBroker(), $this);
325:                         $firstChild = $firstChild ?: $constant;
326: 
327:                         $constantName = $constant->getName();
328:                         if (isset($this->constants[$constantName])) {
329:                             if (!$this->constants[$constantName] instanceof Invalid\ReflectionConstant) {
330:                                 $this->constants[$constantName] = new Invalid\ReflectionConstant($constantName, $this->constants[$constantName]->getFileName(), $this->getBroker());
331:                             }
332: 
333:                             if (!$this->constants[$constantName]->hasReasons()) {
334:                                 $this->constants[$constantName]->addReason(new Exception\ParseException(
335:                                     $this,
336:                                     $tokenStream,
337:                                     sprintf('Constant %s is defined multiple times in the file.', $constantName),
338:                                     Exception\ParseException::ALREADY_EXISTS
339:                                 ));
340:                             }
341:                         } else {
342:                             $this->constants[$constantName] = $constant;
343:                         }
344:                         if ($tokenStream->is(',')) {
345:                             $tokenStream->skipWhitespaces(true);
346:                         } else {
347:                             $tokenStream->next();
348:                         }
349:                     } while ($tokenStream->is(T_STRING));
350:                     break;
351:                 case T_FUNCTION:
352:                     $position = $tokenStream->key() + 1;
353:                     while (isset($skipped[$type = $tokenStream->getType($position)])) {
354:                         $position++;
355:                     }
356:                     if ('(' === $type) {
357:                         // Skipping anonymous functions
358: 
359:                         $tokenStream
360:                             ->seek($position)
361:                             ->findMatchingBracket()
362:                             ->skipWhiteSpaces(true);
363: 
364:                         if ($tokenStream->is(T_USE)) {
365:                             $tokenStream
366:                                 ->skipWhitespaces(true)
367:                                 ->findMatchingBracket()
368:                                 ->skipWhitespaces(true);
369:                         }
370: 
371:                         $tokenStream
372:                             ->findMatchingBracket()
373:                             ->next();
374: 
375:                         continue;
376:                     }
377: 
378:                     $function = new ReflectionFunction($tokenStream, $this->getBroker(), $this);
379:                     $firstChild = $firstChild ?: $function;
380: 
381:                     $functionName = $function->getName();
382:                     if (isset($this->functions[$functionName])) {
383:                         if (!$this->functions[$functionName] instanceof Invalid\ReflectionFunction) {
384:                             $this->functions[$functionName] = new Invalid\ReflectionFunction($functionName, $this->functions[$functionName]->getFileName(), $this->getBroker());
385:                         }
386: 
387:                         if (!$this->functions[$functionName]->hasReasons()) {
388:                             $this->functions[$functionName]->addReason(new Exception\ParseException(
389:                                 $this,
390:                                 $tokenStream,
391:                                 sprintf('Function %s is defined multiple times in the file.', $functionName),
392:                                 Exception\ParseException::ALREADY_EXISTS
393:                             ));
394:                         }
395:                     } else {
396:                         $this->functions[$functionName] = $function;
397:                     }
398:                     $tokenStream->next();
399:                     break;
400:                 default:
401:                     $tokenStream->next();
402:                     break;
403:             }
404:         }
405: 
406:         if ($firstChild) {
407:             $this->startPosition = min($this->startPosition, $firstChild->getStartPosition());
408:         }
409: 
410:         return $this;
411:     }
412: }
413: 
PHP Token Reflection API documentation generated by ApiGen 2.8.0