1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
15:
16: namespace TokenReflection\Php;
17:
18: use TokenReflection;
19: use TokenReflection\Broker, TokenReflection\Exception;
20: use Reflector, ReflectionClass as InternalReflectionClass, ReflectionProperty as InternalReflectionProperty, ReflectionMethod as InternalReflectionMethod;
21:
22: 23: 24: 25: 26:
27: class ReflectionClass extends InternalReflectionClass implements IReflection, TokenReflection\IReflectionClass
28: {
29: 30: 31: 32: 33:
34: private $broker;
35:
36: 37: 38: 39: 40:
41: private $interfaces;
42:
43: 44: 45: 46: 47:
48: private $methods;
49:
50: 51: 52: 53: 54:
55: private $constants;
56:
57: 58: 59: 60: 61:
62: private $properties;
63:
64: 65: 66: 67: 68: 69:
70: public function __construct($className, Broker $broker)
71: {
72: parent::__construct($className);
73: $this->broker = $broker;
74: }
75:
76: 77: 78: 79: 80:
81: public function getExtension()
82: {
83: return ReflectionExtension::create(parent::getExtension(), $this->broker);
84: }
85:
86: 87: 88: 89: 90: 91:
92: public function hasAnnotation($name)
93: {
94: return false;
95: }
96:
97: 98: 99: 100: 101: 102:
103: public function getAnnotation($name)
104: {
105: return null;
106: }
107:
108: 109: 110: 111: 112:
113: public function getAnnotations()
114: {
115: return array();
116: }
117:
118: 119: 120: 121: 122:
123: public function isException()
124: {
125: return 'Exception' === $this->getName() || $this->isSubclassOf('Exception');
126: }
127:
128: 129: 130: 131: 132: 133: 134: 135:
136: public function isCloneable()
137: {
138: if ($this->isInterface() || $this->isAbstract()) {
139: return false;
140: }
141:
142: $methods = $this->getMethods();
143: return isset($methods['__clone']) ? $methods['__clone']->isPublic() : true;
144: }
145:
146: 147: 148: 149: 150:
151: public function isTokenized()
152: {
153: return false;
154: }
155:
156: 157: 158: 159: 160:
161: public function isDeprecated()
162: {
163: return false;
164: }
165:
166: 167: 168: 169: 170: 171: 172:
173: public function isSubclassOf($class)
174: {
175: if (is_object($class)) {
176: if (!$class instanceof InternalReflectionClass && !$class instanceof IReflectionClass) {
177: throw new Exception\RuntimeException('Parameter must be a string or an instance of class reflection.', Exception\RuntimeException::INVALID_ARGUMENT, $this);
178: }
179:
180: $class = $class->getName();
181: }
182:
183: return in_array($class, $this->getParentClassNameList());
184: }
185:
186: 187: 188: 189: 190:
191: public function getParentClass()
192: {
193: $parent = parent::getParentClass();
194: return $parent ? self::create($parent, $this->broker) : null;
195: }
196:
197: 198: 199: 200: 201:
202: public function getParentClassName()
203: {
204: $parent = $this->getParentClass();
205: return $parent ? $parent->getName() : null;
206: }
207:
208: 209: 210: 211: 212:
213: public function getParentClasses()
214: {
215: $broker = $this->broker;
216: return array_map(function($className) use ($broker) {
217: return $broker->getClass($className);
218: }, $this->getParentClassNameList());
219: }
220:
221: 222: 223: 224: 225:
226: public function getParentClassNameList()
227: {
228: return class_parents($this->getName());
229: }
230:
231: 232: 233: 234: 235: 236: 237:
238: public function implementsInterface($interface)
239: {
240: if (is_object($interface)) {
241: if (!$interface instanceof InternalReflectionClass && !$interface instanceof IReflectionClass) {
242: throw new Exception\RuntimeException('Parameter must be a string or an instance of class reflection.', Exception\RuntimeException::INVALID_ARGUMENT, $this);
243: }
244:
245: $interfaceName = $interface->getName();
246:
247: if (!$interface->isInterface()) {
248: throw new Exception\RuntimeException(sprintf('"%s" is not an interface.', $interfaceName), Exception\RuntimeException::INVALID_ARGUMENT, $this);
249: }
250: } else {
251: $reflection = $this->getBroker()->getClass($interface);
252: if (!$reflection->isInterface()) {
253: throw new Exception\RuntimeException(sprintf('"%s" is not an interface.', $interface), Exception\RuntimeException::INVALID_ARGUMENT, $this);
254: }
255:
256: $interfaceName = $interface;
257: }
258:
259: $interfaces = $this->getInterfaces();
260: return isset($interfaces[$interfaceName]);
261: }
262:
263: 264: 265: 266: 267:
268: public function getInterfaces()
269: {
270: if (null === $this->interfaces) {
271: $broker = $this->broker;
272: $interfaceNames = $this->getInterfaceNames();
273:
274: if (empty($interfaceNames)) {
275: $this->interfaces = array();
276: } else {
277: $this->interfaces = array_combine($interfaceNames, array_map(function($interfaceName) use ($broker) {
278: return $broker->getClass($interfaceName);
279: }, $interfaceNames));
280: }
281: }
282:
283: return $this->interfaces;
284: }
285:
286: 287: 288: 289: 290:
291: public function getOwnInterfaces()
292: {
293: $parent = $this->getParentClass();
294: return $parent ? array_diff_key($this->getInterfaces(), $parent->getInterfaces()) : $this->getInterfaces();
295: }
296:
297: 298: 299: 300: 301:
302: public function getOwnInterfaceNames()
303: {
304: return array_keys($this->getOwnInterfaces());
305: }
306:
307: 308: 309: 310: 311:
312: public function getConstructor()
313: {
314: return ReflectionMethod::create(parent::getConstructor(), $this->broker);
315: }
316:
317: 318: 319: 320: 321:
322: public function getDestructor()
323: {
324: foreach ($this->getMethods() as $method) {
325: if ($method->isDestructor()) {
326: return $method;
327: }
328: }
329:
330: return null;
331: }
332:
333: 334: 335: 336: 337: 338: 339:
340: public function getMethod($name)
341: {
342: foreach ($this->getMethods() as $method) {
343: if ($method->getName() === $name) {
344: return $method;
345: }
346: }
347:
348: throw new Exception\RuntimeException(sprintf('Method %s does not exist.', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this);
349: }
350:
351: 352: 353: 354: 355: 356:
357: public function getMethods($filter = null)
358: {
359: if (null === $this->methods) {
360: $broker = $this->broker;
361: $this->methods = array_map(function(InternalReflectionMethod $method) use ($broker) {
362: return ReflectionMethod::create($method, $broker);
363: }, parent::getMethods());
364: }
365:
366: if (null === $filter) {
367: return $this->methods;
368: }
369:
370: return array_filter($this->methods, function(ReflectionMethod $method) use ($filter) {
371: return (bool) ($method->getModifiers() & $filter);
372: });
373: }
374:
375: 376: 377: 378: 379: 380:
381: public function hasOwnMethod($name)
382: {
383: foreach ($this->getOwnMethods() as $method) {
384: if ($name === $method->getName()) {
385: return true;
386: }
387: }
388:
389: return false;
390: }
391:
392: 393: 394: 395: 396: 397:
398: public function getOwnMethods($filter = null)
399: {
400: $me = $this->getName();
401: return array_filter($this->getMethods($filter), function(ReflectionMethod $method) use ($me) {
402: return $method->getDeclaringClass()->getName() === $me;
403: });
404: }
405:
406: 407: 408: 409: 410: 411: 412:
413: public function hasTraitMethod($name)
414: {
415: return false;
416: }
417:
418: 419: 420: 421: 422: 423: 424:
425: public function getTraitMethods($filter = null)
426: {
427: return array();
428: }
429:
430: 431: 432: 433: 434: 435: 436:
437: public function getConstantReflection($name)
438: {
439: if ($this->hasConstant($name)) {
440: return new ReflectionConstant($name, $this->getConstant($name), $this->broker, $this);
441: }
442:
443: throw new Exception\RuntimeException(sprintf('Constant "%s" does not exist.', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this);
444: }
445:
446: 447: 448: 449: 450:
451: public function getConstantReflections()
452: {
453: if (null === $this->constants) {
454: $this->constants = array();
455: foreach ($this->getConstants() as $name => $value) {
456: $this->constants[$name] = $this->getConstantReflection($name);
457: }
458: }
459:
460: return array_values($this->constants);
461: }
462:
463: 464: 465: 466: 467: 468:
469: public function hasOwnConstant($name)
470: {
471: $constants = $this->getOwnConstants();
472: return isset($constants[$name]);
473: }
474:
475: 476: 477: 478: 479:
480: public function getOwnConstants()
481: {
482: return array_diff_assoc($this->getConstants(), $this->getParentClass() ? $this->getParentClass()->getConstants() : array());
483: }
484:
485: 486: 487: 488: 489:
490: public function getOwnConstantReflections()
491: {
492: $constants = array();
493: foreach ($this->getOwnConstants() as $name => $value) {
494: $constants[] = $this->getConstantReflection($name);
495: }
496: return $constants;
497: }
498:
499: 500: 501: 502: 503: 504: 505:
506: public function getProperty($name)
507: {
508: foreach ($this->getProperties() as $property) {
509: if ($name === $property->getName()) {
510: return $property;
511: }
512: }
513:
514: throw new Exception\RuntimeException(sprintf('Property %s does not exist.', $name), Exception\RuntimeException::DOES_NOT_EXIST, $this);
515: }
516:
517: 518: 519: 520: 521: 522:
523: public function getProperties($filter = null)
524: {
525: if (null === $this->properties) {
526: $broker = $this->broker;
527: $this->properties = array_map(function(InternalReflectionProperty $property) use ($broker) {
528: return ReflectionProperty::create($property, $broker);
529: }, parent::getProperties());
530: }
531:
532: if (null === $filter) {
533: return $this->properties;
534: }
535:
536: return array_filter($this->properties, function(ReflectionProperty $property) use ($filter) {
537: return (bool) ($property->getModifiers() & $filter);
538: });
539: }
540:
541: 542: 543: 544: 545: 546:
547: public function hasOwnProperty($name)
548: {
549: foreach ($this->getOwnProperties() as $property) {
550: if ($name === $property->getName()) {
551: return true;
552: }
553: }
554:
555: return false;
556: }
557:
558: 559: 560: 561: 562: 563:
564: public function getOwnProperties($filter = null)
565: {
566: $me = $this->getName();
567: return array_filter($this->getProperties($filter), function(ReflectionProperty $property) use ($me) {
568: return $property->getDeclaringClass()->getName() === $me;
569: });
570: }
571:
572: 573: 574: 575: 576: 577: 578:
579: public function hasTraitProperty($name)
580: {
581: return false;
582: }
583:
584: 585: 586: 587: 588: 589: 590:
591: public function getTraitProperties($filter = null)
592: {
593: return array();
594: }
595:
596: 597: 598: 599: 600:
601: public function getStaticProperties()
602: {
603: return $this->getProperties(InternalReflectionProperty::IS_STATIC);
604: }
605:
606: 607: 608: 609: 610:
611: public function getDirectSubclasses()
612: {
613: $that = $this->name;
614: return array_filter($this->getBroker()->getClasses(Broker\Backend::INTERNAL_CLASSES | Broker\Backend::TOKENIZED_CLASSES), function(IReflectionClass $class) use ($that) {
615: if (!$class->isSubclassOf($that)) {
616: return false;
617: }
618:
619: return null === $class->getParentClassName() || !$class->getParentClass()->isSubClassOf($that);
620: });
621: }
622:
623: 624: 625: 626: 627:
628: public function getDirectSubclassNames()
629: {
630: return array_keys($this->getDirectSubclasses());
631: }
632:
633: 634: 635: 636: 637:
638: public function getIndirectSubclasses()
639: {
640: $that = $this->name;
641: return array_filter($this->getBroker()->getClasses(Broker\Backend::INTERNAL_CLASSES | Broker\Backend::TOKENIZED_CLASSES), function(IReflectionClass $class) use ($that) {
642: if (!$class->isSubclassOf($that)) {
643: return false;
644: }
645:
646: return null !== $class->getParentClassName() && $class->getParentClass()->isSubClassOf($that);
647: });
648: }
649:
650: 651: 652: 653: 654:
655: public function getIndirectSubclassNames()
656: {
657: return array_keys($this->getIndirectSubclasses());
658: }
659:
660: 661: 662: 663: 664:
665: public function getDirectImplementers()
666: {
667: if (!$this->isInterface()) {
668: return array();
669: }
670:
671: $that = $this->name;
672: return array_filter($this->getBroker()->getClasses(Broker\Backend::INTERNAL_CLASSES | Broker\Backend::TOKENIZED_CLASSES), function(IReflectionClass $class) use ($that) {
673: if (!$class->implementsInterface($that)) {
674: return false;
675: }
676:
677: return null === $class->getParentClassName() || !$class->getParentClass()->implementsInterface($that);
678: });
679: }
680:
681: 682: 683: 684: 685:
686: public function getDirectImplementerNames()
687: {
688: return array_keys($this->getDirectImplementers());
689: }
690:
691: 692: 693: 694: 695:
696: public function getIndirectImplementers()
697: {
698: if (!$this->isInterface()) {
699: return array();
700: }
701:
702: $that = $this->name;
703: return array_filter($this->getBroker()->getClasses(Broker\Backend::INTERNAL_CLASSES | Broker\Backend::TOKENIZED_CLASSES), function(IReflectionClass $class) use ($that) {
704: if (!$class->implementsInterface($that)) {
705: return false;
706: }
707:
708: return null !== $class->getParentClassName() && $class->getParentClass()->implementsInterface($that);
709: });
710: }
711:
712: 713: 714: 715: 716:
717: public function getIndirectImplementerNames()
718: {
719: return array_keys($this->getIndirectImplementers());
720: }
721:
722: 723: 724: 725: 726: 727: 728:
729: public function isComplete()
730: {
731: return true;
732: }
733:
734: 735: 736: 737: 738: 739: 740:
741: public function isValid()
742: {
743: return true;
744: }
745:
746: 747: 748: 749: 750:
751: public function getNamespaceAliases()
752: {
753: return array();
754: }
755:
756: 757: 758: 759: 760:
761: public function getBroker()
762: {
763: return $this->broker;
764: }
765:
766: 767: 768: 769: 770: 771:
772: final public function __get($key)
773: {
774: return TokenReflection\ReflectionElement::get($this, $key);
775: }
776:
777: 778: 779: 780: 781: 782:
783: final public function __isset($key)
784: {
785: return TokenReflection\ReflectionElement::exists($this, $key);
786: }
787:
788: 789: 790: 791: 792:
793: public function getTraits()
794: {
795: return NATIVE_TRAITS ? parent::getTraits() : array();
796: }
797:
798: 799: 800: 801: 802:
803: public function getOwnTraits()
804: {
805: if (!NATIVE_TRAITS) {
806: return array();
807: }
808:
809: $parent = $this->getParentClass();
810: return $parent ? array_diff_key($this->getTraits(), $parent->getTraits()) : $this->getTraits();
811: }
812:
813: 814: 815: 816: 817:
818: public function getTraitNames()
819: {
820: return NATIVE_TRAITS ? parent::getTraitNames() : array();
821: }
822:
823: 824: 825: 826: 827:
828: public function getOwnTraitNames()
829: {
830: return array_keys($this->getOwnTraits());
831: }
832:
833: 834: 835: 836: 837:
838: public function getTraitAliases()
839: {
840: return NATIVE_TRAITS ? parent::getTraitAliases() : array();
841: }
842:
843: 844: 845: 846: 847:
848: public function isTrait()
849: {
850: return NATIVE_TRAITS && parent::isTrait();
851: }
852:
853: 854: 855: 856: 857: 858: 859:
860: public function usesTrait($trait)
861: {
862: if (is_object($trait)) {
863: if (!$trait instanceof InternalReflectionClass && !$trait instanceof TokenReflection\IReflectionClass) {
864: throw new Exception\RuntimeException('Parameter must be a string or an instance of trait reflection.', Exception\RuntimeException::INVALID_ARGUMENT, $this);
865: }
866:
867: $traitName = $trait->getName();
868:
869: if (!$trait->isTrait()) {
870: throw new Exception\RuntimeException(sprintf('"%s" is not a trait.', $traitName), Exception\RuntimeException::INVALID_ARGUMENT, $this);
871: }
872: } else {
873: $reflection = $this->getBroker()->getClass($trait);
874: if (!$reflection->isTrait()) {
875: throw new Exception\RuntimeException(sprintf('"%s" is not a trait.', $trait), Exception\RuntimeException::INVALID_ARGUMENT, $this);
876: }
877:
878: $traitName = $trait;
879: }
880:
881: return in_array($traitName, $this->getTraitNames());
882: }
883:
884: 885: 886: 887: 888: 889:
890: public function newInstanceWithoutConstructor()
891: {
892: if ($this->isInternal()) {
893: throw new Exception\RuntimeException('Could not create an instance; only user defined classes can be instantiated.', Exception\RuntimeException::UNSUPPORTED, $this);
894: }
895:
896: foreach ($this->getParentClasses() as $parent) {
897: if ($parent->isInternal()) {
898: throw new Exception\RuntimeException('Could not create an instance; only user defined classes can be instantiated.', Exception\RuntimeException::UNSUPPORTED, $this);
899: }
900: }
901:
902: if (PHP_VERSION_ID >= 50400) {
903: return parent::newInstanceWithoutConstructor();
904: }
905:
906: return unserialize(sprintf('O:%d:"%s":0:{}', strlen($this->getName()), $this->getName()));
907: }
908:
909: 910: 911: 912: 913:
914: public function getPrettyName()
915: {
916: return $this->getName();
917: }
918:
919: 920: 921: 922: 923: 924: 925: 926:
927: public static function create(Reflector $internalReflection, Broker $broker)
928: {
929: if (!$internalReflection instanceof InternalReflectionClass) {
930: throw new Exception\RuntimeException('Invalid reflection instance provided, ReflectionClass expected.', Exception\RuntimeException::INVALID_ARGUMENT);
931: }
932:
933: return $broker->getClass($internalReflection->getName());
934: }
935: }
936: