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: use ReflectionClass as InternalReflectionClass, ReflectionProperty as InternalReflectionProperty, ReflectionMethod as InternalReflectionMethod;
  20: 
  21: /**
  22:  * Tokenized class reflection.
  23:  */
  24: class ReflectionClass extends ReflectionElement implements IReflectionClass
  25: {
  26:     /**
  27:      * Modifier for determining if the reflected object is an interface.
  28:      *
  29:      * @var integer
  30:      * @see http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/Zend/zend_compile.h?revision=306939&view=markup#l122
  31:      */
  32:     const IS_INTERFACE = 0x80;
  33: 
  34:     /**
  35:      * Modifier for determining if the reflected object is a trait.
  36:      *
  37:      * @var integer
  38:      * @see http://svn.php.net/viewvc/php/php-src/trunk/Zend/zend_compile.h?revision=306938&view=markup#l150
  39:      */
  40:     const IS_TRAIT = 0x120;
  41: 
  42:     /**
  43:      * Class implements interfaces.
  44:      *
  45:      * @see http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3/Zend/zend_compile.h?revision=306939&view=markup#l152
  46:      *
  47:      * @var integer
  48:      */
  49:     const IMPLEMENTS_INTERFACES = 0x80000;
  50: 
  51:     /**
  52:      * Class implements traits.
  53:      *
  54:      * @see http://svn.php.net/viewvc/php/php-src/trunk/Zend/zend_compile.h?revision=306938&view=markup#l181
  55:      *
  56:      * @var integer
  57:      */
  58:     const IMPLEMENTS_TRAITS = 0x400000;
  59: 
  60:     /**
  61:      * Class namespace name.
  62:      *
  63:      * @var string
  64:      */
  65:     private $namespaceName;
  66: 
  67:     /**
  68:      * Class modifiers.
  69:      *
  70:      * @var integer
  71:      */
  72:     private $modifiers = 0;
  73: 
  74:     /**
  75:      * Class type (class/interface/trait).
  76:      *
  77:      * @var integer
  78:      */
  79:     private $type = 0;
  80: 
  81:     /**
  82:      * Determines if modifiers are complete.
  83:      *
  84:      * @var boolean
  85:      */
  86:     private $modifiersComplete = false;
  87: 
  88:     /**
  89:      * Parent class name.
  90:      *
  91:      * @var string
  92:      */
  93:     private $parentClassName;
  94: 
  95:     /**
  96:      * Implemented interface names.
  97:      *
  98:      * @var array
  99:      */
 100:     private $interfaces = array();
 101: 
 102:     /**
 103:      * Used trait names.
 104:      *
 105:      * @var array
 106:      */
 107:     private $traits = array();
 108: 
 109:     /**
 110:      * Aliases used at trait methods.
 111:      *
 112:      * Compatible with the internal reflection.
 113:      *
 114:      * @var array
 115:      */
 116:     private $traitAliases = array();
 117: 
 118:     /**
 119:      * Trait importing rules.
 120:      *
 121:      * Format:
 122:      * [<trait>::]<method> => array(
 123:      *    array(<new-name>, [<access-level>])|null
 124:      *    [, ...]
 125:      * )
 126:      *
 127:      * @var array
 128:      */
 129:     private $traitImports = array();
 130: 
 131:     /**
 132:      * Stores if the class definition is complete.
 133:      *
 134:      * @var array
 135:      */
 136:     private $methods = array();
 137: 
 138:     /**
 139:      * Constant reflections.
 140:      *
 141:      * @var array
 142:      */
 143:     private $constants = array();
 144: 
 145:     /**
 146:      * Properties reflections.
 147:      *
 148:      * @var array
 149:      */
 150:     private $properties = array();
 151: 
 152:     /**
 153:      * Stores if the class definition is complete.
 154:      *
 155:      * @var boolean
 156:      */
 157:     private $definitionComplete = false;
 158: 
 159:     /**
 160:      * Imported namespace/class aliases.
 161:      *
 162:      * @var array
 163:      */
 164:     private $aliases = array();
 165: 
 166:     /**
 167:      * Returns the unqualified name (UQN).
 168:      *
 169:      * @return string
 170:      */
 171:     public function getShortName()
 172:     {
 173:         $name = $this->getName();
 174:         if ($this->namespaceName !== ReflectionNamespace::NO_NAMESPACE_NAME) {
 175:             $name = substr($name, strlen($this->namespaceName) + 1);
 176:         }
 177: 
 178:         return $name;
 179:     }
 180: 
 181:     /**
 182:      * Returns the namespace name.
 183:      *
 184:      * @return string
 185:      */
 186:     public function getNamespaceName()
 187:     {
 188:         return $this->namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME ? '' : $this->namespaceName;
 189:     }
 190: 
 191:     /**
 192:      * Returns if the class is defined within a namespace.
 193:      *
 194:      * @return boolean
 195:      */
 196:     public function inNamespace()
 197:     {
 198:         return null !== $this->namespaceName && ReflectionNamespace::NO_NAMESPACE_NAME !== $this->namespaceName;
 199:     }
 200: 
 201:     /**
 202:      * Returns modifiers.
 203:      *
 204:      * @return array
 205:      */
 206:     public function getModifiers()
 207:     {
 208:         if (false === $this->modifiersComplete) {
 209:             if (($this->modifiers & InternalReflectionClass::IS_EXPLICIT_ABSTRACT) && !($this->modifiers & InternalReflectionClass::IS_IMPLICIT_ABSTRACT)) {
 210:                 foreach ($this->getMethods() as $reflectionMethod) {
 211:                     if ($reflectionMethod->isAbstract()) {
 212:                         $this->modifiers |= InternalReflectionClass::IS_IMPLICIT_ABSTRACT;
 213:                     }
 214:                 }
 215: 
 216:                 if (!empty($this->interfaces)) {
 217:                     $this->modifiers |= InternalReflectionClass::IS_IMPLICIT_ABSTRACT;
 218:                 }
 219:             }
 220: 
 221:             if (!empty($this->interfaces)) {
 222:                 $this->modifiers |= self::IMPLEMENTS_INTERFACES;
 223:             }
 224: 
 225:             if ($this->isInterface() && !empty($this->methods)) {
 226:                 $this->modifiers |= InternalReflectionClass::IS_IMPLICIT_ABSTRACT;
 227:             }
 228: 
 229:             if (!empty($this->traits)) {
 230:                 $this->modifiers |= self::IMPLEMENTS_TRAITS;
 231:             }
 232: 
 233:             $this->modifiersComplete = null === $this->parentClassName || $this->getParentClass()->isComplete();
 234: 
 235:             if ($this->modifiersComplete) {
 236:                 foreach ($this->getInterfaces() as $interface) {
 237:                     if (!$interface->isComplete()) {
 238:                         $this->modifiersComplete = false;
 239:                         break;
 240:                     }
 241:                 }
 242:             }
 243:             if ($this->modifiersComplete) {
 244:                 foreach ($this->getTraits() as $trait) {
 245:                     if (!$trait->isComplete()) {
 246:                         $this->modifiersComplete = false;
 247:                         break;
 248:                     }
 249:                 }
 250:             }
 251:         }
 252: 
 253:         return $this->modifiers;
 254:     }
 255: 
 256:     /**
 257:      * Returns if the class is abstract.
 258:      *
 259:      * @return boolean
 260:      */
 261:     public function isAbstract()
 262:     {
 263:         if ($this->modifiers & InternalReflectionClass::IS_EXPLICIT_ABSTRACT) {
 264:             return true;
 265:         } elseif ($this->isInterface() && !empty($this->methods)) {
 266:             return true;
 267:         }
 268: 
 269:         return false;
 270:     }
 271: 
 272:     /**
 273:      * Returns if the class is final.
 274:      *
 275:      * @return boolean
 276:      */
 277:     public function isFinal()
 278:     {
 279:         return (bool) ($this->modifiers & InternalReflectionClass::IS_FINAL);
 280:     }
 281: 
 282:     /**
 283:      * Returns if the class is an interface.
 284:      *
 285:      * @return boolean
 286:      */
 287:     public function isInterface()
 288:     {
 289:         return (bool) ($this->modifiers & self::IS_INTERFACE);
 290:     }
 291: 
 292:     /**
 293:      * Returns if the class is an exception or its descendant.
 294:      *
 295:      * @return boolean
 296:      */
 297:     public function isException()
 298:     {
 299:         return 'Exception' === $this->name || $this->isSubclassOf('Exception');
 300:     }
 301: 
 302:     /**
 303:      * Returns if it is possible to create an instance of this class.
 304:      *
 305:      * @return boolean
 306:      */
 307:     public function isInstantiable()
 308:     {
 309:         if ($this->isInterface() || $this->isAbstract()) {
 310:             return false;
 311:         }
 312: 
 313:         if (null === ($constructor = $this->getConstructor())) {
 314:             return true;
 315:         }
 316: 
 317:         return $constructor->isPublic();
 318:     }
 319: 
 320:     /**
 321:      * Returns if objects of this class are cloneable.
 322:      *
 323:      * Introduced in PHP 5.4.
 324:      *
 325:      * @return boolean
 326:      * @see http://svn.php.net/viewvc/php/php-src/trunk/ext/reflection/php_reflection.c?revision=307971&view=markup#l4059
 327:      */
 328:     public function isCloneable()
 329:     {
 330:         if ($this->isInterface() || $this->isAbstract()) {
 331:             return false;
 332:         }
 333: 
 334:         if ($this->hasMethod('__clone')) {
 335:             return $this->getMethod('__clone')->isPublic();
 336:         }
 337: 
 338:         return true;
 339:     }
 340: 
 341:     /**
 342:      * Returns if the class is iterateable.
 343:      *
 344:      * Returns true if the class implements the Traversable interface.
 345:      *
 346:      * @return boolean
 347:      * @todo traits
 348:      */
 349:     public function isIterateable()
 350:     {
 351:         return $this->implementsInterface('Traversable');
 352:     }
 353: 
 354:     /**
 355:      * Returns if the current class is a subclass of the given class.
 356:      *
 357:      * @param string|object $class Class name or reflection object
 358:      * @return boolean
 359:      * @throws \TokenReflection\Exception\RuntimeException If the provided parameter is not a reflection class instance.
 360:      */
 361:     public function isSubclassOf($class)
 362:     {
 363:         if (is_object($class)) {
 364:             if ($class instanceof InternalReflectionClass || $class instanceof IReflectionClass) {
 365:                 $class = $class->getName();
 366:             } else {
 367:                 $class = get_class($class);
 368:             }
 369:         }
 370: 
 371:         if ($class === $this->parentClassName) {
 372:             return true;
 373:         }
 374: 
 375:         $parent = $this->getParentClass();
 376:         return false === $parent ? false : $parent->isSubclassOf($class);
 377:     }
 378: 
 379:     /**
 380:      * Returns the parent class reflection.
 381:      *
 382:      * @return \TokenReflection\ReflectionClass|boolean
 383:      */
 384:     public function getParentClass()
 385:     {
 386:         $className = $this->getParentClassName();
 387:         if (null === $className) {
 388:             return false;
 389:         }
 390: 
 391:         return $this->getBroker()->getClass($className);
 392:     }
 393: 
 394:     /**
 395:      * Returns the parent class name.
 396:      *
 397:      * @return string|null
 398:      */
 399:     public function getParentClassName()
 400:     {
 401:         return $this->parentClassName;
 402:     }
 403: 
 404:     /**
 405:      * Returns the parent classes reflections.
 406:      *
 407:      * @return array
 408:      */
 409:     public function getParentClasses()
 410:     {
 411:         $parent = $this->getParentClass();
 412:         if (false === $parent) {
 413:             return array();
 414:         }
 415: 
 416:         return array_merge(array($parent->getName() => $parent), $parent->getParentClasses());
 417:     }
 418: 
 419:     /**
 420:      * Returns the parent classes names.
 421:      *
 422:      * @return array
 423:      */
 424:     public function getParentClassNameList()
 425:     {
 426:         $parent = $this->getParentClass();
 427:         if (false === $parent) {
 428:             return array();
 429:         }
 430: 
 431:         return array_merge(array($parent->getName()), $parent->getParentClassNameList());
 432:     }
 433: 
 434:     /**
 435:      * Returns if the class implements the given interface.
 436:      *
 437:      * @param string|object $interface Interface name or reflection object
 438:      * @return boolean
 439:      * @throws \TokenReflection\Exception\RuntimeException If the provided parameter is not an interface.
 440:      */
 441:     public function implementsInterface($interface)
 442:     {
 443:         if (is_object($interface)) {
 444:             if (!$interface instanceof InternalReflectionClass && !$interface instanceof IReflectionClass) {
 445:                 throw new Exception\RuntimeException(sprintf('Parameter must be a string or an instance of class reflection, "%s" provided.', get_class($interface)), Exception\RuntimeException::INVALID_ARGUMENT, $this);
 446:             }
 447: 
 448:             if (!$interface->isInterface()) {
 449:                 throw new Exception\RuntimeException(sprintf('"%s" is not an interface.', $interfaceName), Exception\RuntimeException::INVALID_ARGUMENT, $this);
 450:             }
 451: 
 452:             $interfaceName = $interface->getName();
 453:         } else {
 454:             $interfaceName = $interface;
 455:         }
 456: 
 457:         return in_array($interfaceName, $this->getInterfaceNames());
 458:     }
 459: 
 460:     /**
 461:      * Returns interface reflections.
 462:      *
 463:      * @return array
 464:      */
 465:     public function getInterfaces()
 466:     {
 467:         $interfaceNames = $this->getInterfaceNames();
 468:         if (empty($interfaceNames)) {
 469:             return array();
 470:         }
 471: 
 472:         $broker = $this->getBroker();
 473:         return array_combine($interfaceNames, array_map(function($interfaceName) use ($broker) {
 474:             return $broker->getClass($interfaceName);
 475:         }, $interfaceNames));
 476:     }
 477: 
 478:     /**
 479:      * Returns interface names.
 480:      *
 481:      * @return array
 482:      */
 483:     public function getInterfaceNames()
 484:     {
 485:         $parentClass = $this->getParentClass();
 486: 
 487:         $names = false !== $parentClass ? array_reverse(array_flip($parentClass->getInterfaceNames())) : array();
 488:         foreach ($this->interfaces as $interfaceName) {
 489:             $names[$interfaceName] = true;
 490:             foreach (array_reverse($this->getBroker()->getClass($interfaceName)->getInterfaceNames()) as $parentInterfaceName) {
 491:                 $names[$parentInterfaceName] = true;
 492:             }
 493:         }
 494: 
 495:         return array_keys($names);
 496:     }
 497: 
 498:     /**
 499:      * Returns reflections of interfaces implemented by this class, not its parents.
 500:      *
 501:      * @return array
 502:      */
 503:     public function getOwnInterfaces()
 504:     {
 505:         $interfaceNames = $this->getOwnInterfaceNames();
 506:         if (empty($interfaceNames)) {
 507:             return array();
 508:         }
 509: 
 510:         $broker = $this->getBroker();
 511:         return array_combine($interfaceNames, array_map(function($interfaceName) use ($broker) {
 512:             return $broker->getClass($interfaceName);
 513:         }, $interfaceNames));
 514:     }
 515: 
 516:     /**
 517:      * Returns names of interfaces implemented by this class, not its parents.
 518:      *
 519:      * @return array
 520:      */
 521:     public function getOwnInterfaceNames()
 522:     {
 523:         return $this->interfaces;
 524:     }
 525: 
 526:     /**
 527:      * Returns the class constructor reflection.
 528:      *
 529:      * @return \TokenReflection\ReflectionMethod|null
 530:      */
 531:     public function getConstructor()
 532:     {
 533:         foreach ($this->getMethods() as $method) {
 534:             if ($method->isConstructor()) {
 535:                 return $method;
 536:             }
 537:         }
 538: 
 539:         return null;
 540:     }
 541: 
 542:     /**
 543:      * Returns the class destructor reflection.
 544:      *
 545:      * @return \TokenReflection\ReflectionMethod|null
 546:      */
 547:     public function getDestructor()
 548:     {
 549:         foreach ($this->getMethods() as $method) {
 550:             if ($method->isDestructor()) {
 551:                 return $method;
 552:             }
 553:         }
 554: 
 555:         return null;
 556:     }
 557: 
 558:     /**
 559:      * Returns if the class implements the given method.
 560:      *
 561:      * @param string $name Method name
 562:      * @return boolean
 563:      */
 564:     public function hasMethod($name)
 565:     {
 566:         foreach ($this->getMethods() as $method) {
 567:             if ($name === $method->getName()) {
 568:                 return true;
 569:             }
 570:         }
 571: 
 572:         return false;
 573:     }
 574: 
 575:     /**
 576:      * Returns a method reflection.
 577:      *
 578:      * @param string $name Method name
 579:      * @return \TokenReflection\ReflectionMethod
 580:      * @throws \TokenReflection\Exception\RuntimeException If the requested method does not exist.
 581:      */
 582:     public function getMethod($name)
 583:     {
 584:         if (isset($this->methods[$name])) {
 585:             return $this->methods[$name];
 586:         }
 587: 
 588:         foreach ($this->getMethods() as $method) {
 589:             if ($name === $method->getName()) {
 590:                 return $method;
 591:             }
 592:         }
 593: 
 594:         throw new Exception\RuntimeException(sprintf('There is no method "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this);
 595:     }
 596: 
 597:     /**
 598:      * Returns method reflections.
 599:      *
 600:      * @param integer $filter Methods filter
 601:      * @return array
 602:      */
 603:     public function getMethods($filter = null)
 604:     {
 605:         $methods = $this->methods;
 606: 
 607:         foreach ($this->getTraitMethods() as $traitMethod) {
 608:             if (!isset($methods[$traitMethod->getName()])) {
 609:                 $methods[$traitMethod->getName()] = $traitMethod;
 610:             }
 611:         }
 612: 
 613:         if (null !== $this->parentClassName) {
 614:             foreach ($this->getParentClass()->getMethods(null) as $parentMethod) {
 615:                 if (!isset($methods[$parentMethod->getName()])) {
 616:                     $methods[$parentMethod->getName()] = $parentMethod;
 617:                 }
 618:             }
 619:         }
 620:         foreach ($this->getOwnInterfaces() as $interface) {
 621:             foreach ($interface->getMethods(null) as $parentMethod) {
 622:                 if (!isset($methods[$parentMethod->getName()])) {
 623:                     $methods[$parentMethod->getName()] = $parentMethod;
 624:                 }
 625:             }
 626:         }
 627: 
 628:         if (null !== $filter) {
 629:             $methods = array_filter($methods, function(IReflectionMethod $method) use ($filter) {
 630:                 return $method->is($filter);
 631:             });
 632:         }
 633: 
 634:         return array_values($methods);
 635:     }
 636: 
 637:     /**
 638:      * Returns if the class implements (and not its parents) the given method.
 639:      *
 640:      * @param string $name Method name
 641:      * @return boolean
 642:      */
 643:     public function hasOwnMethod($name)
 644:     {
 645:         return isset($this->methods[$name]);
 646:     }
 647: 
 648:     /**
 649:      * Returns reflections of methods declared by this class, not its parents.
 650:      *
 651:      * @param integer $filter Methods filter
 652:      * @return array
 653:      */
 654:     public function getOwnMethods($filter = null)
 655:     {
 656:         $methods = $this->methods;
 657: 
 658:         if (null !== $filter) {
 659:             $methods = array_filter($methods, function(ReflectionMethod $method) use ($filter) {
 660:                 return $method->is($filter);
 661:             });
 662:         }
 663: 
 664:         return array_values($methods);
 665:     }
 666: 
 667:     /**
 668:      * Returns if the class imports the given method from traits.
 669:      *
 670:      * @param string $name Method name
 671:      * @return boolean
 672:      */
 673:     public function hasTraitMethod($name)
 674:     {
 675:         if (isset($this->methods[$name])) {
 676:             return false;
 677:         }
 678: 
 679:         foreach ($this->getOwnTraits() as $trait) {
 680:             if ($trait->hasMethod($name)) {
 681:                 return true;
 682:             }
 683:         }
 684: 
 685:         return false;
 686:     }
 687: 
 688:     /**
 689:      * Returns reflections of method imported from traits.
 690:      *
 691:      * @param integer $filter Methods filter
 692:      * @return array
 693:      * @throws \TokenReflection\Exception\RuntimeException If trait method was already imported.
 694:      */
 695:     public function getTraitMethods($filter = null)
 696:     {
 697:         $methods = array();
 698: 
 699:         foreach ($this->getOwnTraits() as $trait) {
 700:             $traitName = $trait->getName();
 701:             foreach ($trait->getMethods(null) as $traitMethod) {
 702:                 $methodName = $traitMethod->getName();
 703: 
 704:                 $imports = array();
 705:                 if (isset($this->traitImports[$traitName . '::' . $methodName])) {
 706:                     $imports = $this->traitImports[$traitName . '::' . $methodName];
 707:                 }
 708:                 if (isset($this->traitImports[$methodName])) {
 709:                     $imports = empty($imports) ? $this->traitImports[$methodName] : array_merge($imports, $this->traitImports[$methodName]);
 710:                 }
 711: 
 712:                 foreach ($imports as $import) {
 713:                     if (null !== $import) {
 714:                         list($newName, $accessLevel) = $import;
 715: 
 716:                         if ('' === $newName) {
 717:                             $newName = $methodName;
 718:                             $imports[] = null;
 719:                         }
 720: 
 721:                         if (!isset($this->methods[$newName])) {
 722:                             if (isset($methods[$newName])) {
 723:                                 throw new Exception\RuntimeException(sprintf('Trait method "%s" was already imported.', $newName), Exception\RuntimeException::ALREADY_EXISTS, $this);
 724:                             }
 725: 
 726:                             $methods[$newName] = $traitMethod->alias($this, $newName, $accessLevel);
 727:                         }
 728:                     }
 729:                 }
 730: 
 731:                 if (!in_array(null, $imports)) {
 732:                     if (!isset($this->methods[$methodName])) {
 733:                         if (isset($methods[$methodName])) {
 734:                             throw new Exception\RuntimeException(sprintf('Trait method "%s" was already imported.', $methodName), Exception\RuntimeException::ALREADY_EXISTS, $this);
 735:                         }
 736: 
 737:                         $methods[$methodName] = $traitMethod->alias($this);
 738:                     }
 739:                 }
 740:             }
 741:         }
 742: 
 743:         if (null !== $filter) {
 744:             $methods = array_filter($methods, function(IReflectionMethod $method) use ($filter) {
 745:                 return (bool) ($method->getModifiers() & $filter);
 746:             });
 747:         }
 748: 
 749:         return array_values($methods);
 750:     }
 751: 
 752:     /**
 753:      * Returns if the class defines the given constant.
 754:      *
 755:      * @param string $name Constant name.
 756:      * @return boolean
 757:      */
 758:     public function hasConstant($name)
 759:     {
 760:         if (isset($this->constants[$name])) {
 761:             return true;
 762:         }
 763: 
 764:         foreach ($this->getConstantReflections() as $constant) {
 765:             if ($name === $constant->getName()) {
 766:                 return true;
 767:             }
 768:         }
 769: 
 770:         return false;
 771:     }
 772: 
 773:     /**
 774:      * Returns a constant value.
 775:      *
 776:      * @param string $name Constant name
 777:      * @return mixed|false
 778:      */
 779:     public function getConstant($name)
 780:     {
 781:         try {
 782:             return $this->getConstantReflection($name)->getValue();
 783:         } catch (Exception\BaseException $e) {
 784:             return false;
 785:         }
 786:     }
 787: 
 788:     /**
 789:      * Returns a constant reflection.
 790:      *
 791:      * @param string $name Constant name
 792:      * @return \TokenReflection\ReflectionConstant
 793:      * @throws \TokenReflection\Exception\RuntimeException If the requested constant does not exist.
 794:      */
 795:     public function getConstantReflection($name)
 796:     {
 797:         if (isset($this->constants[$name])) {
 798:             return $this->constants[$name];
 799:         }
 800: 
 801:         foreach ($this->getConstantReflections() as $constant) {
 802:             if ($name === $constant->getName()) {
 803:                 return $constant;
 804:             }
 805:         }
 806: 
 807:         throw new Exception\RuntimeException(sprintf('There is no constant "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this);
 808:     }
 809: 
 810:     /**
 811:      * Returns constant values.
 812:      *
 813:      * @return array
 814:      */
 815:     public function getConstants()
 816:     {
 817:         $constants = array();
 818:         foreach ($this->getConstantReflections() as $constant) {
 819:             $constants[$constant->getName()] = $constant->getValue();
 820:         }
 821:         return $constants;
 822:     }
 823: 
 824:     /**
 825:      * Returns constant reflections.
 826:      *
 827:      * @return array
 828:      */
 829:     public function getConstantReflections()
 830:     {
 831:         if (null === $this->parentClassName && empty($this->interfaces)) {
 832:             return array_values($this->constants);
 833:         } else {
 834:             $reflections = array_values($this->constants);
 835: 
 836:             if (null !== $this->parentClassName) {
 837:                 $reflections = array_merge($reflections, $this->getParentClass()->getConstantReflections());
 838:             }
 839:             foreach ($this->getOwnInterfaces() as $interface) {
 840:                 $reflections = array_merge($reflections, $interface->getConstantReflections());
 841:             }
 842: 
 843:             return $reflections;
 844:         }
 845:     }
 846: 
 847:     /**
 848:      * Returns if the class (and not its parents) defines the given constant.
 849:      *
 850:      * @param string $name Constant name.
 851:      * @return boolean
 852:      */
 853:     public function hasOwnConstant($name)
 854:     {
 855:         return isset($this->constants[$name]);
 856:     }
 857: 
 858:     /**
 859:      * Returns constants declared by this class, not by its parents.
 860:      *
 861:      * @return array
 862:      */
 863:     public function getOwnConstants()
 864:     {
 865:         return array_map(function(ReflectionConstant $constant) {
 866:             return $constant->getValue();
 867:         }, $this->constants);
 868:     }
 869: 
 870:     /**
 871:      * Returns reflections of constants declared by this class, not by its parents.
 872:      *
 873:      * @return array
 874:      */
 875:     public function getOwnConstantReflections()
 876:     {
 877:         return array_values($this->constants);
 878:     }
 879: 
 880:     /**
 881:      * Returns if the class defines the given property.
 882:      *
 883:      * @param string $name Property name
 884:      * @return boolean
 885:      */
 886:     public function hasProperty($name)
 887:     {
 888:         foreach ($this->getProperties() as $property) {
 889:             if ($name === $property->getName()) {
 890:                 return true;
 891:             }
 892:         }
 893: 
 894:         return false;
 895:     }
 896: 
 897:     /**
 898:      * Return a property reflection.
 899:      *
 900:      * @param string $name Property name
 901:      * @return \TokenReflection\ReflectionProperty
 902:      * @throws \TokenReflection\Exception\RuntimeException If the requested property does not exist.
 903:      */
 904:     public function getProperty($name)
 905:     {
 906:         if (isset($this->properties[$name])) {
 907:             return $this->properties[$name];
 908:         }
 909: 
 910:         foreach ($this->getProperties() as $property) {
 911:             if ($name === $property->getName()) {
 912:                 return $property;
 913:             }
 914:         }
 915: 
 916:         throw new Exception\RuntimeException(sprintf('There is no property "%s".', $name, $this->name), Exception\RuntimeException::DOES_NOT_EXIST, $this);
 917:     }
 918: 
 919:     /**
 920:      * Returns property reflections.
 921:      *
 922:      * @param integer $filter Properties filter
 923:      * @return array
 924:      */
 925:     public function getProperties($filter = null)
 926:     {
 927:         $properties = $this->properties;
 928: 
 929:         foreach ($this->getTraitProperties(null) as $traitProperty) {
 930:             if (!isset($properties[$traitProperty->getName()])) {
 931:                 $properties[$traitProperty->getName()] = $traitProperty->alias($this);
 932:             }
 933:         }
 934: 
 935:         if (null !== $this->parentClassName) {
 936:             foreach ($this->getParentClass()->getProperties(null) as $parentProperty) {
 937:                 if (!isset($properties[$parentProperty->getName()])) {
 938:                     $properties[$parentProperty->getName()] = $parentProperty;
 939:                 }
 940:             }
 941:         }
 942: 
 943:         if (null !== $filter) {
 944:             $properties = array_filter($properties, function(IReflectionProperty $property) use ($filter) {
 945:                 return (bool) ($property->getModifiers() & $filter);
 946:             });
 947:         }
 948: 
 949:         return array_values($properties);
 950:     }
 951: 
 952:     /**
 953:      * Returns if the class (and not its parents) defines the given property.
 954:      *
 955:      * @param string $name Property name
 956:      * @return boolean
 957:      */
 958:     public function hasOwnProperty($name)
 959:     {
 960:         return isset($this->properties[$name]);
 961:     }
 962: 
 963:     /**
 964:      * Returns reflections of properties declared by this class, not its parents.
 965:      *
 966:      * @param integer $filter Properties filter
 967:      * @return array
 968:      */
 969:     public function getOwnProperties($filter = null)
 970:     {
 971:         $properties = $this->properties;
 972: 
 973:         if (null !== $filter) {
 974:             $properties = array_filter($properties, function(ReflectionProperty $property) use ($filter) {
 975:                 return (bool) ($property->getModifiers() & $filter);
 976:             });
 977:         }
 978: 
 979:         return array_values($properties);
 980:     }
 981: 
 982:     /**
 983:      * Returns if the class imports the given property from traits.
 984:      *
 985:      * @param string $name Property name
 986:      * @return boolean
 987:      */
 988:     public function hasTraitProperty($name)
 989:     {
 990:         if (isset($this->properties[$name])) {
 991:             return false;
 992:         }
 993: 
 994:         foreach ($this->getOwnTraits() as $trait) {
 995:             if ($trait->hasProperty($name)) {
 996:                 return true;
 997:             }
 998:         }
 999: 
1000:         return false;
1001:     }
1002: 
1003:     /**
1004:      * Returns reflections of properties imported from traits.
1005:      *
1006:      * @param integer $filter Properties filter
1007:      * @return array
1008:      */
1009:     public function getTraitProperties($filter = null)
1010:     {
1011:         $properties = array();
1012: 
1013:         foreach ($this->getOwnTraits() as $trait) {
1014:             foreach ($trait->getProperties(null) as $traitProperty) {
1015:                 if (!isset($this->properties[$traitProperty->getName()]) && !isset($properties[$traitProperty->getName()])) {
1016:                     $properties[$traitProperty->getName()] = $traitProperty->alias($this);
1017:                 }
1018:             }
1019:         }
1020: 
1021:         if (null !== $filter) {
1022:             $properties = array_filter($properties, function(IReflectionProperty $property) use ($filter) {
1023:                 return (bool) ($property->getModifiers() & $filter);
1024:             });
1025:         }
1026: 
1027:         return array_values($properties);
1028:     }
1029: 
1030:     /**
1031:      * Returns default properties.
1032:      *
1033:      * @return array
1034:      */
1035:     public function getDefaultProperties()
1036:     {
1037:         static $accessLevels = array(InternalReflectionProperty::IS_PUBLIC, InternalReflectionProperty::IS_PROTECTED, InternalReflectionProperty::IS_PRIVATE);
1038: 
1039:         $defaults = array();
1040:         $properties = $this->getProperties();
1041:         foreach (array(true, false) as $static) {
1042:             foreach ($properties as $property) {
1043:                 foreach ($accessLevels as $level) {
1044:                     if ($property->isStatic() === $static && ($property->getModifiers() & $level)) {
1045:                         $defaults[$property->getName()] = $property->getDefaultValue();
1046:                     }
1047:                 }
1048:             }
1049:         }
1050: 
1051:         return $defaults;
1052:     }
1053: 
1054:     /**
1055:      * Returns static properties reflections.
1056:      *
1057:      * @return array
1058:      */
1059:     public function getStaticProperties()
1060:     {
1061:         $defaults = array();
1062:         foreach ($this->getProperties(InternalReflectionProperty::IS_STATIC) as $property) {
1063:             if ($property instanceof ReflectionProperty) {
1064:                 $defaults[$property->getName()] = $property->getDefaultValue();
1065:             }
1066:         }
1067: 
1068:         return $defaults;
1069:     }
1070: 
1071:     /**
1072:      * Returns a value of a static property.
1073:      *
1074:      * @param string $name Property name
1075:      * @param mixed $default Default value
1076:      * @return mixed
1077:      * @throws \TokenReflection\Exception\RuntimeException If the requested static property does not exist.
1078:      * @throws \TokenReflection\Exception\RuntimeException If the requested static property is not accessible.
1079:      */
1080:     public function getStaticPropertyValue($name, $default = null)
1081:     {
1082:         if ($this->hasProperty($name) && ($property = $this->getProperty($name)) && $property->isStatic()) {
1083:             if (!$property->isPublic() && !$property->isAccessible()) {
1084:                 throw new Exception\RuntimeException(sprintf('Static property "%s" is not accessible.', $name), Exception\RuntimeException::NOT_ACCESSBILE, $this);
1085:             }
1086: 
1087:             return $property->getDefaultValue();
1088:         }
1089: 
1090:         throw new Exception\RuntimeException(sprintf('There is no static property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this);
1091:     }
1092: 
1093:     /**
1094:      * Returns traits used by this class.
1095:      *
1096:      * @return array
1097:      */
1098:     public function getTraits()
1099:     {
1100:         $traitNames = $this->getTraitNames();
1101:         if (empty($traitNames)) {
1102:             return array();
1103:         }
1104: 
1105:         $broker = $this->getBroker();
1106:         return array_combine($traitNames, array_map(function($traitName) use ($broker) {
1107:             return $broker->getClass($traitName);
1108:         }, $traitNames));
1109:     }
1110: 
1111:     /**
1112:      * Returns traits used by this class and not its parents.
1113:      *
1114:      * @return array
1115:      */
1116:     public function getOwnTraits()
1117:     {
1118:         $ownTraitNames = $this->getOwnTraitNames();
1119:         if (empty($ownTraitNames)) {
1120:             return array();
1121:         }
1122: 
1123:         $broker = $this->getBroker();
1124:         return array_combine($ownTraitNames, array_map(function($traitName) use ($broker) {
1125:             return $broker->getClass($traitName);
1126:         }, $ownTraitNames));
1127:     }
1128: 
1129:     /**
1130:      * Returns names of used traits.
1131:      *
1132:      * @return array
1133:      */
1134:     public function getTraitNames()
1135:     {
1136:         $parentClass = $this->getParentClass();
1137: 
1138:         $names = $parentClass ? $parentClass->getTraitNames() : array();
1139:         foreach ($this->traits as $traitName) {
1140:             $names[] = $traitName;
1141:         }
1142: 
1143:         return array_unique($names);
1144:     }
1145: 
1146:     /**
1147:      * Returns names of traits used by this class an not its parents.
1148:      *
1149:      * @return array
1150:      */
1151:     public function getOwnTraitNames()
1152:     {
1153:         return $this->traits;
1154:     }
1155: 
1156:     /**
1157:      * Returns method aliases from traits.
1158:      *
1159:      * @return array
1160:      */
1161:     public function getTraitAliases()
1162:     {
1163:         return $this->traitAliases;
1164:     }
1165: 
1166:     /**
1167:      * Returns if the class is a trait.
1168:      *
1169:      * @return boolean
1170:      */
1171:     public function isTrait()
1172:     {
1173:         return self::IS_TRAIT === $this->type;
1174:     }
1175: 
1176:     /**
1177:      * Returns if the class definition is valid.
1178:      *
1179:      * @return boolean
1180:      */
1181:     public function isValid()
1182:     {
1183:         if (null !== $this->parentClassName && !$this->getParentClass()->isValid()) {
1184:             return false;
1185:         }
1186: 
1187:         foreach ($this->getInterfaces() as $interface) {
1188:             if (!$interface->isValid()) {
1189:                 return false;
1190:             }
1191:         }
1192: 
1193:         foreach ($this->getTraits() as $trait) {
1194:             if (!$trait->isValid()) {
1195:                 return false;
1196:             }
1197:         }
1198: 
1199:         return true;
1200:     }
1201: 
1202:     /**
1203:      * Returns if the class uses a particular trait.
1204:      *
1205:      * @param \ReflectionClass|\TokenReflection\IReflectionClass|string $trait Trait reflection or name
1206:      * @return boolean
1207:      * @throws \TokenReflection\Exception\RuntimeException If an invalid parameter was provided.
1208:      */
1209:     public function usesTrait($trait)
1210:     {
1211:         if (is_object($trait)) {
1212:             if (!$trait instanceof InternalReflectionClass && !$trait instanceof IReflectionClass) {
1213:                 throw new Exception\RuntimeException(sprintf('Parameter must be a string or an instance of trait reflection, "%s" provided.', get_class($trait)), Exception\RuntimeException::INVALID_ARGUMENT, $this);
1214:             }
1215: 
1216:             $traitName = $trait->getName();
1217: 
1218:             if (!$trait->isTrait()) {
1219:                 throw new Exception\RuntimeException(sprintf('"%s" is not a trait.', $traitName), Exception\RuntimeException::INVALID_ARGUMENT, $this);
1220:             }
1221:         } else {
1222:             $reflection = $this->getBroker()->getClass($trait);
1223:             if (!$reflection->isTrait()) {
1224:                 throw new Exception\RuntimeException(sprintf('"%s" is not a trait.', $trait), Exception\RuntimeException::INVALID_ARGUMENT, $this);
1225:             }
1226: 
1227:             $traitName = $trait;
1228:         }
1229: 
1230:         return in_array($traitName, $this->getTraitNames());
1231:     }
1232: 
1233:     /**
1234:      * Returns reflections of direct subclasses.
1235:      *
1236:      * @return array
1237:      */
1238:     public function getDirectSubclasses()
1239:     {
1240:         $that = $this->name;
1241:         return array_filter($this->getBroker()->getClasses(), function(ReflectionClass $class) use ($that) {
1242:             if (!$class->isSubclassOf($that)) {
1243:                 return false;
1244:             }
1245: 
1246:             return null === $class->getParentClassName() || !$class->getParentClass()->isSubClassOf($that);
1247:         });
1248:     }
1249: 
1250:     /**
1251:      * Returns names of direct subclasses.
1252:      *
1253:      * @return array
1254:      */
1255:     public function getDirectSubclassNames()
1256:     {
1257:         return array_keys($this->getDirectSubclasses());
1258:     }
1259: 
1260:     /**
1261:      * Returns reflections of indirect subclasses.
1262:      *
1263:      * @return array
1264:      */
1265:     public function getIndirectSubclasses()
1266:     {
1267:         $that = $this->name;
1268:         return array_filter($this->getBroker()->getClasses(), function(ReflectionClass $class) use ($that) {
1269:             if (!$class->isSubclassOf($that)) {
1270:                 return false;
1271:             }
1272: 
1273:             return null !== $class->getParentClassName() && $class->getParentClass()->isSubClassOf($that);
1274:         });
1275:     }
1276: 
1277:     /**
1278:      * Returns names of indirect subclasses.
1279:      *
1280:      * @return array
1281:      */
1282:     public function getIndirectSubclassNames()
1283:     {
1284:         return array_keys($this->getIndirectSubclasses());
1285:     }
1286: 
1287:     /**
1288:      * Returns reflections of classes directly implementing this interface.
1289:      *
1290:      * @return array
1291:      */
1292:     public function getDirectImplementers()
1293:     {
1294:         if (!$this->isInterface()) {
1295:             return array();
1296:         }
1297: 
1298:         $that = $this->name;
1299:         return array_filter($this->getBroker()->getClasses(), function(ReflectionClass $class) use ($that) {
1300:             if ($class->isInterface() || !$class->implementsInterface($that)) {
1301:                 return false;
1302:             }
1303: 
1304:             return null === $class->getParentClassName() || !$class->getParentClass()->implementsInterface($that);
1305:         });
1306:     }
1307: 
1308:     /**
1309:      * Returns names of classes directly implementing this interface.
1310:      *
1311:      * @return array
1312:      */
1313:     public function getDirectImplementerNames()
1314:     {
1315:         return array_keys($this->getDirectImplementers());
1316:     }
1317: 
1318:     /**
1319:      * Returns reflections of classes indirectly implementing this interface.
1320:      *
1321:      * @return array
1322:      */
1323:     public function getIndirectImplementers()
1324:     {
1325:         if (!$this->isInterface()) {
1326:             return array();
1327:         }
1328: 
1329:         $that = $this->name;
1330:         return array_filter($this->getBroker()->getClasses(), function(ReflectionClass $class) use ($that) {
1331:             if ($class->isInterface() || !$class->implementsInterface($that)) {
1332:                 return false;
1333:             }
1334: 
1335:             return null !== $class->getParentClassName() && $class->getParentClass()->implementsInterface($that);
1336:         });
1337:     }
1338: 
1339:     /**
1340:      * Returns names of classes indirectly implementing this interface.
1341:      *
1342:      * @return array
1343:      */
1344:     public function getIndirectImplementerNames()
1345:     {
1346:         return array_keys($this->getIndirectImplementers());
1347:     }
1348: 
1349:     /**
1350:      * Returns if the given object is an instance of this class.
1351:      *
1352:      * @param object $object Instance
1353:      * @return boolean
1354:      * @throws \TokenReflection\Exception\RuntimeException If the provided argument is not an object.
1355:      */
1356:     public function isInstance($object)
1357:     {
1358:         if (!is_object($object)) {
1359:             throw new Exception\RuntimeException(sprintf('Parameter must be an object, "%s" provided.', gettype($object)), Exception\RuntimeException::INVALID_ARGUMENT, $this);
1360:         }
1361: 
1362:         return $this->name === get_class($object) || is_subclass_of($object, $this->getName());
1363:     }
1364: 
1365:     /**
1366:      * Creates a new class instance without using a constructor.
1367:      *
1368:      * @return object
1369:      * @throws \TokenReflection\Exception\RuntimeException If the class inherits from an internal class.
1370:      */
1371:     public function newInstanceWithoutConstructor()
1372:     {
1373:         if (!class_exists($this->name, true)) {
1374:             throw new Exception\RuntimeException('Could not create an instance; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this);
1375:         }
1376: 
1377:         $reflection = new \TokenReflection\Php\ReflectionClass($this->getName(), $this->getBroker());
1378:         return $reflection->newInstanceWithoutConstructor();
1379:     }
1380: 
1381:     /**
1382:      * Creates a new instance using variable number of parameters.
1383:      *
1384:      * Use any number of constructor parameters as function parameters.
1385:      *
1386:      * @param mixed $args
1387:      * @return object
1388:      */
1389:     public function newInstance($args)
1390:     {
1391:         return $this->newInstanceArgs(func_get_args());
1392:     }
1393: 
1394:     /**
1395:      * Creates a new instance using an array of parameters.
1396:      *
1397:      * @param array $args Array of constructor parameters
1398:      * @return object
1399:      * @throws \TokenReflection\Exception\RuntimeException If the required class does not exist.
1400:      */
1401:     public function newInstanceArgs(array $args = array())
1402:     {
1403:         if (!class_exists($this->name, true)) {
1404:             throw new Exception\RuntimeException('Could not create an instance; class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST, $this);
1405:         }
1406: 
1407:         $reflection = new InternalReflectionClass($this->name);
1408:         return $reflection->newInstanceArgs($args);
1409:     }
1410: 
1411:     /**
1412:      * Sets a static property value.
1413:      *
1414:      * @param string $name Property name
1415:      * @param mixed $value Property value
1416:      * @throws \TokenReflection\Exception\RuntimeException If the requested static property does not exist.
1417:      * @throws \TokenReflection\Exception\RuntimeException If the requested static property is not accessible.
1418:      */
1419:     public function setStaticPropertyValue($name, $value)
1420:     {
1421:         if ($this->hasProperty($name) && ($property = $this->getProperty($name)) && $property->isStatic()) {
1422:             if (!$property->isPublic() && !$property->isAccessible()) {
1423:                 throw new Exception\RuntimeException(sprintf('Static property "%s" is not accessible.', $name), Exception\RuntimeException::NOT_ACCESSBILE, $this);
1424:             }
1425: 
1426:             $property->setDefaultValue($value);
1427:             return;
1428:         }
1429: 
1430:         throw new Exception\RuntimeException(sprintf('There is no static property "%s".', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this);
1431:     }
1432: 
1433:     /**
1434:      * Returns the string representation of the reflection object.
1435:      *
1436:      * @return string
1437:      */
1438:     public function __toString()
1439:     {
1440:         $implements = '';
1441:         $interfaceNames = $this->getInterfaceNames();
1442:         if (count($interfaceNames) > 0) {
1443:             $implements = sprintf(
1444:                 ' %s %s',
1445:                 $this->isInterface() ? 'extends' : 'implements',
1446:                 implode(', ', $interfaceNames)
1447:             );
1448:         }
1449: 
1450:         $buffer = '';
1451:         $count = 0;
1452:         foreach ($this->getConstantReflections() as $constant) {
1453:             $buffer .= '    ' . $constant->__toString();
1454:             $count++;
1455:         }
1456:         $constants = sprintf("\n\n  - Constants [%d] {\n%s  }", $count, $buffer);
1457: 
1458:         $sBuffer = '';
1459:         $sCount = 0;
1460:         $buffer = '';
1461:         $count = 0;
1462:         foreach ($this->getProperties() as $property) {
1463:             $string = '    ' . preg_replace('~\n(?!$)~', "\n    ", $property->__toString());
1464:             if ($property->isStatic()) {
1465:                 $sBuffer .= $string;
1466:                 $sCount++;
1467:             } else {
1468:                 $buffer .= $string;
1469:                 $count++;
1470:             }
1471:         }
1472:         $staticProperties = sprintf("\n\n  - Static properties [%d] {\n%s  }", $sCount, $sBuffer);
1473:         $properties = sprintf("\n\n  - Properties [%d] {\n%s  }", $count, $buffer);
1474: 
1475:         $sBuffer = '';
1476:         $sCount = 0;
1477:         $buffer = '';
1478:         $count = 0;
1479:         foreach ($this->getMethods() as $method) {
1480:             // Skip private methods of parent classes
1481:             if ($method->getDeclaringClassName() !== $this->getName() && $method->isPrivate()) {
1482:                 continue;
1483:             }
1484:             // Indent
1485:             $string = "\n    ";
1486: 
1487:             $string .= preg_replace('~\n(?!$|\n|\s*\*)~', "\n    ", $method->__toString());
1488:             // Add inherits
1489:             if ($method->getDeclaringClassName() !== $this->getName()) {
1490:                 $string = preg_replace(
1491:                     array('~Method [ <[\w:]+~', '~, overwrites[^,]+~'),
1492:                     array('\0, inherits ' . $method->getDeclaringClassName(), ''),
1493:                     $string
1494:                 );
1495:             }
1496:             if ($method->isStatic()) {
1497:                 $sBuffer .= $string;
1498:                 $sCount++;
1499:             } else {
1500:                 $buffer .= $string;
1501:                 $count++;
1502:             }
1503:         }
1504:         $staticMethods = sprintf("\n\n  - Static methods [%d] {\n%s  }", $sCount, ltrim($sBuffer, "\n"));
1505:         $methods = sprintf("\n\n  - Methods [%d] {\n%s  }", $count, ltrim($buffer, "\n"));
1506: 
1507:         return sprintf(
1508:             "%s%s [ <user>%s %s%s%s %s%s%s ] {\n  @@ %s %d-%d%s%s%s%s%s\n}\n",
1509:             $this->getDocComment() ? $this->getDocComment() . "\n" : '',
1510:             $this->isInterface() ? 'Interface' : 'Class',
1511:             $this->isIterateable() ? ' <iterateable>' : '',
1512:             $this->isAbstract() && !$this->isInterface() ? 'abstract ' : '',
1513:             $this->isFinal() ? 'final ' : '',
1514:             $this->isInterface() ? 'interface' : 'class',
1515:             $this->getName(),
1516:             null !== $this->getParentClassName() ? ' extends ' . $this->getParentClassName() : '',
1517:             $implements,
1518:             $this->getFileName(),
1519:             $this->getStartLine(),
1520:             $this->getEndLine(),
1521:             $constants,
1522:             $staticProperties,
1523:             $staticMethods,
1524:             $properties,
1525:             $methods
1526:         );
1527:     }
1528: 
1529:     /**
1530:      * Exports a reflected object.
1531:      *
1532:      * @param \TokenReflection\Broker $broker Broker instance
1533:      * @param string|object $className Class name or class instance
1534:      * @param boolean $return Return the export instead of outputting it
1535:      * @return string|null
1536:      * @throws \TokenReflection\Exception\RuntimeException If requested parameter doesn't exist.
1537:      */
1538:     public static function export(Broker $broker, $className, $return = false)
1539:     {
1540:         if (is_object($className)) {
1541:             $className = get_class($className);
1542:         }
1543: 
1544:         $class = $broker->getClass($className);
1545:         if ($class instanceof Invalid\ReflectionClass) {
1546:             throw new Exception\RuntimeException('Class is invalid.', Exception\RuntimeException::UNSUPPORTED);
1547:         } elseif ($class instanceof Dummy\ReflectionClass) {
1548:             throw new Exception\RuntimeException('Class does not exist.', Exception\RuntimeException::DOES_NOT_EXIST);
1549:         }
1550: 
1551:         if ($return) {
1552:             return $class->__toString();
1553:         }
1554: 
1555:         echo $class->__toString();
1556:     }
1557: 
1558:     /**
1559:      * Returns if the class definition is complete.
1560:      *
1561:      * @return boolean
1562:      */
1563:     public function isComplete()
1564:     {
1565:         if (!$this->definitionComplete) {
1566:             if (null !== $this->parentClassName && !$this->getParentClass()->isComplete()) {
1567:                 return false;
1568:             }
1569: 
1570:             foreach ($this->getOwnInterfaces() as $interface) {
1571:                 if (!$interface->isComplete()) {
1572:                     return false;
1573:                 }
1574:             }
1575: 
1576:             $this->definitionComplete = true;
1577:         }
1578: 
1579:         return $this->definitionComplete;
1580:     }
1581: 
1582:     /**
1583:      * Returns imported namespaces and aliases from the declaring namespace.
1584:      *
1585:      * @return array
1586:      */
1587:     public function getNamespaceAliases()
1588:     {
1589:         return $this->aliases;
1590:     }
1591: 
1592:     /**
1593:      * Processes the parent reflection object.
1594:      *
1595:      * @param \TokenReflection\IReflection $parent Parent reflection object
1596:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
1597:      * @return \TokenReflection\ReflectionClass
1598:      * @throws \TokenReflection\ParseException On invalid parent reflection provided
1599:      */
1600:     protected function processParent(IReflection $parent, Stream $tokenStream)
1601:     {
1602:         if (!$parent instanceof ReflectionFileNamespace) {
1603:             throw new Exception\ParseException($this, $tokenStream, sprintf('Invalid parent reflection provided: "%s".', get_class($parent)), Exception\ParseException::INVALID_PARENT);
1604:         }
1605: 
1606:         $this->namespaceName = $parent->getName();
1607:         $this->aliases = $parent->getNamespaceAliases();
1608:         return parent::processParent($parent, $tokenStream);
1609:     }
1610: 
1611:     /**
1612:      * Parses reflected element metadata from the token stream.
1613:      *
1614:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
1615:      * @param \TokenReflection\IReflection $parent Parent reflection object
1616:      * @return \TokenReflection\ReflectionClass
1617:      */
1618:     protected function parse(Stream $tokenStream, IReflection $parent)
1619:     {
1620:         return $this
1621:             ->parseModifiers($tokenStream)
1622:             ->parseName($tokenStream)
1623:             ->parseParent($tokenStream, $parent)
1624:             ->parseInterfaces($tokenStream, $parent);
1625:     }
1626: 
1627:     /**
1628:      * Parses class modifiers (abstract, final) and class type (class, interface).
1629:      *
1630:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
1631:      * @return \TokenReflection\ReflectionClass
1632:      */
1633:     private function parseModifiers(Stream $tokenStream)
1634:     {
1635:         while (true) {
1636:             switch ($tokenStream->getType()) {
1637:                 case null:
1638:                     break 2;
1639:                 case T_ABSTRACT:
1640:                     $this->modifiers = InternalReflectionClass::IS_EXPLICIT_ABSTRACT;
1641:                     break;
1642:                 case T_FINAL:
1643:                     $this->modifiers = InternalReflectionClass::IS_FINAL;
1644:                     break;
1645:                 case T_INTERFACE:
1646:                     $this->modifiers = self::IS_INTERFACE;
1647:                     $this->type = self::IS_INTERFACE;
1648:                     $tokenStream->skipWhitespaces(true);
1649:                     break 2;
1650:                 case T_TRAIT:
1651:                     $this->modifiers = self::IS_TRAIT;
1652:                     $this->type = self::IS_TRAIT;
1653:                     $tokenStream->skipWhitespaces(true);
1654:                     break 2;
1655:                 case T_CLASS:
1656:                     $tokenStream->skipWhitespaces(true);
1657:                     break 2;
1658:                 default:
1659:                     break;
1660:             }
1661: 
1662:             $tokenStream->skipWhitespaces(true);
1663:         }
1664: 
1665:         return $this;
1666:     }
1667: 
1668:     /**
1669:      * Parses the class/interface name.
1670:      *
1671:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
1672:      * @return \TokenReflection\ReflectionClass
1673:      * @throws \TokenReflection\Exception\ParseException If the class name could not be determined.
1674:      */
1675:     protected function parseName(Stream $tokenStream)
1676:     {
1677:         if (!$tokenStream->is(T_STRING)) {
1678:             throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
1679:         }
1680: 
1681:         if ($this->namespaceName === ReflectionNamespace::NO_NAMESPACE_NAME) {
1682:             $this->name = $tokenStream->getTokenValue();
1683:         } else {
1684:             $this->name = $this->namespaceName . '\\' . $tokenStream->getTokenValue();
1685:         }
1686: 
1687:         $tokenStream->skipWhitespaces(true);
1688: 
1689:         return $this;
1690:     }
1691: 
1692:     /**
1693:      * Parses the parent class.
1694:      *
1695:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
1696:      * @param \TokenReflection\IReflection $parent Parent reflection object
1697:      * @return \TokenReflection\ReflectionClass
1698:      */
1699:     private function parseParent(Stream $tokenStream, ReflectionElement $parent = null)
1700:     {
1701:         if (!$tokenStream->is(T_EXTENDS)) {
1702:             return $this;
1703:         }
1704: 
1705:         while (true) {
1706:             $tokenStream->skipWhitespaces(true);
1707: 
1708:             $parentClassName = '';
1709:             while (true) {
1710:                 switch ($tokenStream->getType()) {
1711:                     case T_STRING:
1712:                     case T_NS_SEPARATOR:
1713:                         $parentClassName .= $tokenStream->getTokenValue();
1714:                         break;
1715:                     default:
1716:                         break 2;
1717:                 }
1718: 
1719:                 $tokenStream->skipWhitespaces(true);
1720:             }
1721: 
1722:             $parentClassName = Resolver::resolveClassFQN($parentClassName, $this->aliases, $this->namespaceName);
1723: 
1724:             if ($this->isInterface()) {
1725:                 $this->interfaces[] = $parentClassName;
1726: 
1727:                 if (',' === $tokenStream->getTokenValue()) {
1728:                     continue;
1729:                 }
1730:             } else {
1731:                 $this->parentClassName = $parentClassName;
1732:             }
1733: 
1734:             break;
1735:         }
1736: 
1737:         return $this;
1738:     }
1739: 
1740:     /**
1741:      * Parses implemented interfaces.
1742:      *
1743:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
1744:      * @param \TokenReflection\IReflection $parent Parent reflection object
1745:      * @return \TokenReflection\ReflectionClass
1746:      * @throws \TokenReflection\Exception\ParseException On error while parsing interfaces.
1747:      */
1748:     private function parseInterfaces(Stream $tokenStream, ReflectionElement $parent = null)
1749:     {
1750:         if (!$tokenStream->is(T_IMPLEMENTS)) {
1751:             return $this;
1752:         }
1753: 
1754:         if ($this->isInterface()) {
1755:             throw new Exception\ParseException($this, $tokenStream, 'Interfaces cannot implement interfaces.', Exception\ParseException::LOGICAL_ERROR);
1756:         }
1757: 
1758:         while (true) {
1759:             $interfaceName = '';
1760: 
1761:             $tokenStream->skipWhitespaces(true);
1762:             while (true) {
1763:                 switch ($tokenStream->getType()) {
1764:                     case T_STRING:
1765:                     case T_NS_SEPARATOR:
1766:                         $interfaceName .= $tokenStream->getTokenValue();
1767:                         break;
1768:                     default:
1769:                         break 2;
1770:                 }
1771: 
1772:                 $tokenStream->skipWhitespaces(true);
1773:             }
1774: 
1775:             $this->interfaces[] = Resolver::resolveClassFQN($interfaceName, $this->aliases, $this->namespaceName);
1776: 
1777:             $type = $tokenStream->getType();
1778:             if ('{' === $type) {
1779:                 break;
1780:             } elseif (',' !== $type) {
1781:                 throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found, expected "{" or ";".', Exception\ParseException::UNEXPECTED_TOKEN);
1782:             }
1783:         }
1784: 
1785:         return $this;
1786:     }
1787: 
1788:     /**
1789:      * Parses child reflection objects from the token stream.
1790:      *
1791:      * @param \TokenReflection\Stream\StreamBase $tokenStream Token substream
1792:      * @param \TokenReflection\IReflection $parent Parent reflection object
1793:      * @return \TokenReflection\ReflectionClass
1794:      * @throws \TokenReflection\Exception\ParseException If a parse error was detected.
1795:      */
1796:     protected function parseChildren(Stream $tokenStream, IReflection $parent)
1797:     {
1798:         while (true) {
1799:             switch ($type = $tokenStream->getType()) {
1800:                 case null:
1801:                     break 2;
1802:                 case T_COMMENT:
1803:                 case T_DOC_COMMENT:
1804:                     $docblock = $tokenStream->getTokenValue();
1805:                     if (preg_match('~^' . preg_quote(self::DOCBLOCK_TEMPLATE_START, '~') . '~', $docblock)) {
1806:                         array_unshift($this->docblockTemplates, new ReflectionAnnotation($this, $docblock));
1807:                     } elseif (self::DOCBLOCK_TEMPLATE_END === $docblock) {
1808:                         array_shift($this->docblockTemplates);
1809:                     }
1810:                     $tokenStream->next();
1811:                     break;
1812:                 case '}':
1813:                     break 2;
1814:                 case T_PUBLIC:
1815:                 case T_PRIVATE:
1816:                 case T_PROTECTED:
1817:                 case T_STATIC:
1818:                 case T_VAR:
1819:                 case T_VARIABLE:
1820:                     static $searching = array(T_VARIABLE => true, T_FUNCTION => true);
1821: 
1822:                     if (T_VAR !== $tokenStream->getType()) {
1823:                         $position = $tokenStream->key();
1824:                         while (null !== ($type = $tokenStream->getType($position)) && !isset($searching[$type])) {
1825:                             $position++;
1826:                         }
1827:                     }
1828: 
1829:                     if (T_VARIABLE === $type || T_VAR === $type) {
1830:                         $property = new ReflectionProperty($tokenStream, $this->getBroker(), $this);
1831:                         $this->properties[$property->getName()] = $property;
1832:                         $tokenStream->next();
1833:                         break;
1834:                     }
1835:                     // Break missing on purpose
1836:                 case T_FINAL:
1837:                 case T_ABSTRACT:
1838:                 case T_FUNCTION:
1839:                     $method = new ReflectionMethod($tokenStream, $this->getBroker(), $this);
1840:                     $this->methods[$method->getName()] = $method;
1841:                     $tokenStream->next();
1842:                     break;
1843:                 case T_CONST:
1844:                     $tokenStream->skipWhitespaces(true);
1845:                     while ($tokenStream->is(T_STRING)) {
1846:                         $constant = new ReflectionConstant($tokenStream, $this->getBroker(), $this);
1847:                         $this->constants[$constant->getName()] = $constant;
1848:                         if ($tokenStream->is(',')) {
1849:                             $tokenStream->skipWhitespaces(true);
1850:                         } else {
1851:                             $tokenStream->next();
1852:                         }
1853:                     }
1854:                     break;
1855:                 case T_USE:
1856:                     $tokenStream->skipWhitespaces(true);
1857: 
1858:                     while (true) {
1859:                         $traitName = '';
1860:                         $type = $tokenStream->getType();
1861:                         while (T_STRING === $type || T_NS_SEPARATOR === $type) {
1862:                             $traitName .= $tokenStream->getTokenValue();
1863:                             $type = $tokenStream->skipWhitespaces(true)->getType();
1864:                         }
1865: 
1866:                         if ('' === trim($traitName, '\\')) {
1867:                             throw new Exception\ParseException($this, $tokenStream, 'An empty trait name found.', Exception\ParseException::LOGICAL_ERROR);
1868:                         }
1869: 
1870:                         $this->traits[] = Resolver::resolveClassFQN($traitName, $this->aliases, $this->namespaceName);
1871: 
1872:                         if (';' === $type) {
1873:                             // End of "use"
1874:                             $tokenStream->skipWhitespaces();
1875:                             break;
1876:                         } elseif (',' === $type) {
1877:                             // Next trait name follows
1878:                             $tokenStream->skipWhitespaces();
1879:                             continue;
1880:                         } elseif ('{' !== $type) {
1881:                             // Unexpected token
1882:                             throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found: "%s".', Exception\ParseException::UNEXPECTED_TOKEN);
1883:                         }
1884: 
1885:                         // Aliases definition
1886:                         $type = $tokenStream->skipWhitespaces(true)->getType();
1887:                         while (true) {
1888:                             if ('}' === $type) {
1889:                                 $tokenStream->skipWhitespaces();
1890:                                 break 2;
1891:                             }
1892: 
1893:                             $leftSide = '';
1894:                             $rightSide = array('', null);
1895:                             $alias = true;
1896: 
1897:                             while (T_STRING === $type || T_NS_SEPARATOR === $type || T_DOUBLE_COLON === $type) {
1898:                                 $leftSide .= $tokenStream->getTokenValue();
1899:                                 $type = $tokenStream->skipWhitespaces(true)->getType();
1900:                             }
1901: 
1902:                             if (T_INSTEADOF === $type) {
1903:                                 $alias = false;
1904:                             } elseif (T_AS !== $type) {
1905:                                 throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
1906:                             }
1907: 
1908:                             $type = $tokenStream->skipWhitespaces(true)->getType();
1909: 
1910:                             if (T_PUBLIC === $type || T_PROTECTED === $type || T_PRIVATE === $type) {
1911:                                 if (!$alias) {
1912:                                     throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
1913:                                 }
1914: 
1915:                                 switch ($type) {
1916:                                     case T_PUBLIC:
1917:                                         $type = InternalReflectionMethod::IS_PUBLIC;
1918:                                         break;
1919:                                     case T_PROTECTED:
1920:                                         $type = InternalReflectionMethod::IS_PROTECTED;
1921:                                         break;
1922:                                     case T_PRIVATE:
1923:                                         $type = InternalReflectionMethod::IS_PRIVATE;
1924:                                         break;
1925:                                     default:
1926:                                         break;
1927:                                 }
1928: 
1929:                                 $rightSide[1] = $type;
1930:                                 $type = $tokenStream->skipWhitespaces(true)->getType();
1931:                             }
1932: 
1933:                             while (T_STRING === $type || (T_NS_SEPARATOR === $type && !$alias)) {
1934:                                 $rightSide[0] .= $tokenStream->getTokenValue();
1935:                                 $type = $tokenStream->skipWhitespaces(true)->getType();
1936:                             }
1937: 
1938:                             if (empty($leftSide)) {
1939:                                 throw new Exception\ParseException($this, $tokenStream, 'An empty method name was found.', Exception\ParseException::LOGICAL_ERROR);
1940:                             }
1941: 
1942:                             if ($alias) {
1943:                                 // Alias
1944:                                 if ($pos = strpos($leftSide, '::')) {
1945:                                     $methodName = substr($leftSide, $pos + 2);
1946:                                     $className = Resolver::resolveClassFQN(substr($leftSide, 0, $pos), $this->aliases, $this->namespaceName);
1947:                                     $leftSide = $className . '::' . $methodName;
1948: 
1949:                                     $this->traitAliases[$rightSide[0]] = $leftSide;
1950:                                 } else {
1951:                                     $this->traitAliases[$rightSide[0]] = '(null)::' . $leftSide;
1952:                                 }
1953: 
1954:                                 $this->traitImports[$leftSide][] = $rightSide;
1955:                             } else {
1956:                                 // Insteadof
1957:                                 if ($pos = strpos($leftSide, '::')) {
1958:                                     $methodName = substr($leftSide, $pos + 2);
1959:                                 } else {
1960:                                     throw new Exception\ParseException($this, $tokenStream, 'A T_DOUBLE_COLON has to be present when using T_INSTEADOF.', Exception\ParseException::UNEXPECTED_TOKEN);
1961:                                 }
1962: 
1963:                                 $this->traitImports[Resolver::resolveClassFQN($rightSide[0], $this->aliases, $this->namespaceName) . '::' . $methodName][] = null;
1964:                             }
1965: 
1966:                             if (',' === $type) {
1967:                                 $tokenStream->skipWhitespaces(true);
1968:                                 continue;
1969:                             } elseif (';' !== $type) {
1970:                                 throw new Exception\ParseException($this, $tokenStream, 'Unexpected token found.', Exception\ParseException::UNEXPECTED_TOKEN);
1971:                             }
1972: 
1973:                             $type = $tokenStream->skipWhitespaces()->getType();
1974:                         }
1975:                     }
1976: 
1977:                     break;
1978:                 default:
1979:                     $tokenStream->next();
1980:                     break;
1981:             }
1982:         }
1983: 
1984:         return $this;
1985:     }
1986: }
1987: 
PHP Token Reflection API documentation generated by ApiGen 2.8.0