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\Broker, TokenReflection\Exception;
 19: use RecursiveDirectoryIterator, RecursiveIteratorIterator;
 20: 
 21: // Detect if we have native traits support
 22: define('NATIVE_TRAITS', defined('T_TRAIT'));
 23: if (!NATIVE_TRAITS) {
 24:     define('T_TRAIT', -1);
 25:     define('T_TRAIT_C', -2);
 26:     define('T_INSTEADOF', -3);
 27:     define('T_CALLABLE', -4);
 28: }
 29: 
 30: /**
 31:  * Reflection broker.
 32:  *
 33:  * Parses files and directories and stores their structure.
 34:  */
 35: class Broker
 36: {
 37:     /**
 38:      * Turns on saving of parsed token streams.
 39:      *
 40:      * @var integer
 41:      */
 42:     const OPTION_SAVE_TOKEN_STREAM = 0x0001;
 43: 
 44:     /**
 45:      * Turns on parsing function/method body.
 46:      *
 47:      * This effectively turns on parsing of static variables in functions/methods.
 48:      *
 49:      * @var integer
 50:      */
 51:     const OPTION_PARSE_FUNCTION_BODY = 0x0002;
 52: 
 53:     /**
 54:      * Default options.
 55:      *
 56:      * @var integer
 57:      */
 58:     const OPTION_DEFAULT = 0x0003;
 59: 
 60:     /**
 61:      * Cache identifier for namespaces.
 62:      *
 63:      * @var string
 64:      */
 65:     const CACHE_NAMESPACE = 'namespace';
 66: 
 67:     /**
 68:      * Cache identifier for classes.
 69:      *
 70:      * @var string
 71:      */
 72:     const CACHE_CLASS = 'class';
 73: 
 74:     /**
 75:      * Cache identifier for constants.
 76:      *
 77:      * @var string
 78:      */
 79:     const CACHE_CONSTANT = 'constant';
 80: 
 81:     /**
 82:      * Cache identifier for functions.
 83:      *
 84:      * @var string
 85:      */
 86:     const CACHE_FUNCTION = 'function';
 87: 
 88:     /**
 89:      * Namespace/class backend.
 90:      *
 91:      * @var \TokenReflection\Broker\Backend
 92:      */
 93:     private $backend;
 94: 
 95:     /**
 96:      * Tokenized reflection objects cache.
 97:      *
 98:      * @var array
 99:      */
100:     private $cache;
101: 
102:     /**
103:      * Broker/parser options.
104:      *
105:      * @var integer
106:      */
107:     private $options;
108: 
109:     /**
110:      * Constructor.
111:      *
112:      * @param \TokenReflection\Broker\Backend $backend Broker backend instance
113:      * @param integer $options Broker/parsing options
114:      */
115:     public function __construct(Broker\Backend $backend, $options = self::OPTION_DEFAULT)
116:     {
117:         $this->cache = array(
118:             self::CACHE_NAMESPACE => array(),
119:             self::CACHE_CLASS => array(),
120:             self::CACHE_CONSTANT => array(),
121:             self::CACHE_FUNCTION => array()
122:         );
123: 
124:         $this->options = $options;
125: 
126:         $this->backend = $backend
127:             ->setBroker($this)
128:             ->setStoringTokenStreams((bool) ($options & self::OPTION_SAVE_TOKEN_STREAM));
129:     }
130: 
131:     /**
132:      * Returns broker/parser options.
133:      *
134:      * @return integer
135:      */
136:     public function getOptions()
137:     {
138:         return $this->options;
139:     }
140: 
141:     /**
142:      * Returns if a particular option setting is set.
143:      *
144:      * @param integer $option Option setting
145:      * @return boolean
146:      */
147:     public function isOptionSet($option)
148:     {
149:         return (bool) ($this->options & $option);
150:     }
151: 
152:     /**
153:      * Parses a string with the PHP source code using the given file name and returns the appropriate reflection object.
154:      *
155:      * @param string $source PHP source code
156:      * @param string $fileName Used file name
157:      * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s)
158:      * @return boolean|\TokenReflection\ReflectionFile
159:      */
160:     public function processString($source, $fileName, $returnReflectionFile = false)
161:     {
162:         if ($this->backend->isFileProcessed($fileName)) {
163:             $tokens = $this->backend->getFileTokens($fileName);
164:         } else {
165:             $tokens = new Stream\StringStream($source, $fileName);
166:         }
167: 
168:         $reflectionFile = new ReflectionFile($tokens, $this);
169:         if (!$this->backend->isFileProcessed($fileName)) {
170:             $this->backend->addFile($tokens, $reflectionFile);
171: 
172:             // Clear the cache - leave only tokenized reflections
173:             foreach ($this->cache as $type => $cached) {
174:                 if (!empty($cached)) {
175:                     $this->cache[$type] = array_filter($cached, function(IReflection $reflection) {
176:                         return $reflection->isTokenized();
177:                     });
178:                 }
179:             }
180:         }
181: 
182:         return $returnReflectionFile ? $reflectionFile : true;
183:     }
184: 
185:     /**
186:      * Parses a file and returns the appropriate reflection object.
187:      *
188:      * @param string $fileName Filename
189:      * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s)
190:      * @return boolean|\TokenReflection\ReflectionFile
191:      * @throws \TokenReflection\Exception\BrokerException If the file could not be processed.
192:      */
193:     public function processFile($fileName, $returnReflectionFile = false)
194:     {
195:         try {
196:             if ($this->backend->isFileProcessed($fileName)) {
197:                 $tokens = $this->backend->getFileTokens($fileName);
198:             } else {
199:                 $tokens = new Stream\FileStream($fileName);
200:             }
201: 
202:             $reflectionFile = new ReflectionFile($tokens, $this);
203:             if (!$this->backend->isFileProcessed($fileName)) {
204:                 $this->backend->addFile($tokens, $reflectionFile);
205: 
206:                 // Clear the cache - leave only tokenized reflections
207:                 foreach ($this->cache as $type => $cached) {
208:                     if (!empty($cached)) {
209:                         $this->cache[$type] = array_filter($cached, function(IReflection $reflection) {
210:                             return $reflection->isTokenized();
211:                         });
212:                     }
213:                 }
214:             }
215: 
216:             return $returnReflectionFile ? $reflectionFile : true;
217:         } catch (Exception\ParseException $e) {
218:             throw $e;
219:         } catch (Exception\StreamException $e) {
220:             throw new Exception\BrokerException($this, 'Could not process the file.', 0, $e);
221:         }
222:     }
223: 
224:     /**
225:      * Processes a PHAR archive.
226:      *
227:      * @param string $fileName Archive filename.
228:      * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s)
229:      * @return boolean|array of \TokenReflection\ReflectionFile
230:      * @throws \TokenReflection\Exception\BrokerException If the PHAR PHP extension is not loaded.
231:      * @throws \TokenReflection\Exception\BrokerException If the given archive could not be read.
232:      * @throws \TokenReflection\Exception\BrokerException If the given archive could not be processed.
233:      */
234:     public function processPhar($fileName, $returnReflectionFile = false)
235:     {
236:         if (!is_file($fileName)) {
237:             throw new Exception\BrokerException($this, 'File does not exist.', Exception\BrokerException::DOES_NOT_EXIST);
238:         }
239: 
240:         if (!extension_loaded('Phar')) {
241:             throw new Exception\BrokerException($this, 'The PHAR PHP extension is not loaded.', Exception\BrokerException::PHP_EXT_MISSING);
242:         }
243: 
244:         try {
245:             $result = array();
246:             foreach (new RecursiveIteratorIterator(new \Phar($fileName)) as $entry) {
247:                 if ($entry->isFile()) {
248:                     $result[$entry->getPathName()] = $this->processFile($entry->getPathName(), $returnReflectionFile);
249:                 }
250:             }
251: 
252:             return $returnReflectionFile ? $result : true;
253:         } catch (Exception\ParseException $e) {
254:             throw $e;
255:         } catch (Exception\StreamException $e) {
256:             throw new Exception\BrokerException($this, 'Could not process the archive.', 0, $e);
257:         }
258:     }
259: 
260:     /**
261:      * Processes recursively a directory and returns an array of file reflection objects.
262:      *
263:      * @param string $path Directora path
264:      * @param string|array $filters Filename filters
265:      * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s)
266:      * @return boolean|array of \TokenReflection\ReflectionFile
267:      * @throws \TokenReflection\Exception\BrokerException If the given directory does not exist.
268:      * @throws \TokenReflection\Exception\BrokerException If the given directory could not be processed.
269:      */
270:     public function processDirectory($path, $filters = array(), $returnReflectionFile = false)
271:     {
272:         $realPath = realpath($path);
273:         if (!is_dir($realPath)) {
274:             throw new Exception\BrokerException($this, 'File does not exist.', Exception\BrokerException::DOES_NOT_EXIST);
275:         }
276: 
277:         try {
278:             $result = array();
279:             foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($realPath)) as $entry) {
280:                 if ($entry->isFile()) {
281:                     $process = empty($filters);
282:                     if (!$process) {
283:                         foreach ((array) $filters as $filter) {
284:                             $whitelisting = '!' !== $filter{0};
285:                             if (fnmatch($whitelisting ? $filter : substr($filter, 1), $entry->getPathName(), FNM_NOESCAPE)) {
286:                                 $process = $whitelisting;
287:                             }
288:                         }
289:                     }
290: 
291:                     if ($process) {
292:                         $result[$entry->getPathName()] = $this->processFile($entry->getPathName(), $returnReflectionFile);
293:                     }
294:                 }
295:             }
296: 
297:             return $returnReflectionFile ? $result : true;
298:         } catch (Exception\ParseException $e) {
299:             throw $e;
300:         } catch (Exception\StreamException $e) {
301:             throw new Exception\BrokerException($this, 'Could not process the directory.', 0, $e);
302:         }
303:     }
304: 
305:     /**
306:      * Process a file, directory or a PHAR archive.
307:      *
308:      * @param string $path Path
309:      * @param boolean $returnReflectionFile Returns the appropriate \TokenReflection\ReflectionFile instance(s)
310:      * @return boolean|array|\TokenReflection\ReflectionFile
311:      * @throws \TokenReflection\Exception\BrokerException If the target does not exist.
312:      */
313:     public function process($path, $returnReflectionFile = false)
314:     {
315:         if (is_dir($path)) {
316:             return $this->processDirectory($path, array(), $returnReflectionFile);
317:         } elseif (is_file($path)) {
318:             if (preg_match('~\\.phar(?:$|\\.)~i', $path)) {
319:                 return $this->processPhar($path, $returnReflectionFile);
320:             }
321: 
322:             return $this->processFile($path, $returnReflectionFile);
323:         } else {
324:             throw new Exception\BrokerException($this, 'The given directory/file does not exist.', Exception\BrokerException::DOES_NOT_EXIST);
325:         }
326:     }
327: 
328:     /**
329:      * Returns if the broker contains a namespace of the given name.
330:      *
331:      * @param string $namespaceName Namespace name
332:      * @return boolean
333:      */
334:     public function hasNamespace($namespaceName)
335:     {
336:         return isset($this->cache[self::CACHE_NAMESPACE][$namespaceName]) || $this->backend->hasNamespace($namespaceName);
337:     }
338: 
339:     /**
340:      * Returns a reflection object of the given namespace.
341:      *
342:      * @param string $namespaceName Namespace name
343:      * @return \TokenReflection\ReflectionNamespace|null
344:      */
345:     public function getNamespace($namespaceName)
346:     {
347:         $namespaceName = ltrim($namespaceName, '\\');
348: 
349:         if (isset($this->cache[self::CACHE_NAMESPACE][$namespaceName])) {
350:             return $this->cache[self::CACHE_NAMESPACE][$namespaceName];
351:         }
352: 
353:         $namespace = $this->backend->getNamespace($namespaceName);
354:         if (null !== $namespace) {
355:             $this->cache[self::CACHE_NAMESPACE][$namespaceName] = $namespace;
356:         }
357: 
358:         return $namespace;
359:     }
360: 
361:     /**
362:      * Returns if the broker contains a class of the given name.
363:      *
364:      * @param string $className Class name
365:      * @return boolean
366:      */
367:     public function hasClass($className)
368:     {
369:         return isset($this->cache[self::CACHE_CLASS][$className]) || $this->backend->hasClass($className);
370:     }
371: 
372:     /**
373:      * Returns a reflection object of the given class (FQN expected).
374:      *
375:      * @param string $className CLass bame
376:      * @return \TokenReflection\ReflectionClass|null
377:      */
378:     public function getClass($className)
379:     {
380:         $className = ltrim($className, '\\');
381: 
382:         if (isset($this->cache[self::CACHE_CLASS][$className])) {
383:             return $this->cache[self::CACHE_CLASS][$className];
384:         }
385: 
386:         $this->cache[self::CACHE_CLASS][$className] = $this->backend->getClass($className);
387:         return $this->cache[self::CACHE_CLASS][$className];
388:     }
389: 
390:     /**
391:      * Returns all classes from all namespaces.
392:      *
393:      * @param integer $types Returned class types (multiple values may be OR-ed)
394:      * @return array
395:      */
396:     public function getClasses($types = Broker\Backend::TOKENIZED_CLASSES)
397:     {
398:         return $this->backend->getClasses($types);
399:     }
400: 
401:     /**
402:      * Returns if the broker contains a constant of the given name.
403:      *
404:      * @param string $constantName Constant name
405:      * @return boolean
406:      */
407:     public function hasConstant($constantName)
408:     {
409:         return isset($this->cache[self::CACHE_CONSTANT][$constantName]) || $this->backend->hasConstant($constantName);
410:     }
411: 
412:     /**
413:      * Returns a reflection object of a constant (FQN expected).
414:      *
415:      * @param string $constantName Constant name
416:      * @return \TokenReflection\ReflectionConstant|null
417:      */
418:     public function getConstant($constantName)
419:     {
420:         $constantName = ltrim($constantName, '\\');
421: 
422:         if (isset($this->cache[self::CACHE_CONSTANT][$constantName])) {
423:             return $this->cache[self::CACHE_CONSTANT][$constantName];
424:         }
425: 
426:         if ($constant = $this->backend->getConstant($constantName)) {
427:             $this->cache[self::CACHE_CONSTANT][$constantName] = $constant;
428:         }
429: 
430:         return $constant;
431:     }
432: 
433:     /**
434:      * Returns all constants from all namespaces.
435:      *
436:      * @return array
437:      */
438:     public function getConstants()
439:     {
440:         return $this->backend->getConstants();
441:     }
442: 
443:     /**
444:      * Returns if the broker contains a function of the given name.
445:      *
446:      * @param string $functionName Function name
447:      * @return boolean
448:      */
449:     public function hasFunction($functionName)
450:     {
451:         return isset($this->cache[self::CACHE_FUNCTION][$functionName]) || $this->backend->hasFunction($functionName);
452:     }
453: 
454:     /**
455:      * Returns a reflection object of a function (FQN expected).
456:      *
457:      * @param string $functionName Function name
458:      * @return \TokenReflection\ReflectionFunction|null
459:      */
460:     public function getFunction($functionName)
461:     {
462:         $functionName = ltrim($functionName, '\\');
463: 
464:         if (isset($this->cache[self::CACHE_FUNCTION][$functionName])) {
465:             return $this->cache[self::CACHE_FUNCTION][$functionName];
466:         }
467: 
468:         if ($function = $this->backend->getFunction($functionName)) {
469:             $this->cache[self::CACHE_FUNCTION][$functionName] = $function;
470:         }
471: 
472:         return $function;
473:     }
474: 
475:     /**
476:      * Returns all functions from all namespaces.
477:      *
478:      * @return array
479:      */
480:     public function getFunctions()
481:     {
482:         return $this->backend->getFunctions();
483:     }
484: 
485:     /**
486:      * Returns if the broker contains a file reflection of the given name.
487:      *
488:      * @param string $fileName File name
489:      * @return boolean
490:      */
491:     public function hasFile($fileName)
492:     {
493:         return $this->backend->hasFile($fileName);
494:     }
495: 
496:     /**
497:      * Returns a reflection object of a file.
498:      *
499:      * @param string $fileName File name
500:      * @return \TokenReflection\ReflectionFile|null
501:      */
502:     public function getFile($fileName)
503:     {
504:         return $this->backend->getFile($fileName);
505:     }
506: 
507:     /**
508:      * Returns all processed files reflections.
509:      *
510:      * @return array
511:      */
512:     public function getFiles()
513:     {
514:         return $this->backend->getFiles();
515:     }
516: 
517:     /**
518:      * Returns an array of tokens from a processed file.
519:      *
520:      * @param string $fileName File name
521:      * @return \TokenReflection\Stream\StreamBase|null
522:      */
523:     public function getFileTokens($fileName)
524:     {
525:         return $this->backend->getFileTokens($fileName);
526:     }
527: 
528:     /**
529:      * Returns a real system path.
530:      *
531:      * @param string $path Source path
532:      * @return string|boolean
533:      */
534:     public static function getRealPath($path)
535:     {
536:         if (0 === strpos($path, 'phar://')) {
537:             return is_file($path) || is_dir($path) ? $path : false;
538:         } else {
539:             return realpath($path);
540:         }
541:     }
542: }
543: 
PHP Token Reflection API documentation generated by ApiGen 2.8.0