@@ -78,9 +78,18 @@ final class ClassReflection
7878 /** @var ExtendedMethodReflection[] */
7979 private array $ methods = [];
8080
81- /** @var ExtendedPropertyReflection[] */
81+ /**
82+ * @var ExtendedPropertyReflection[]
83+ * @deprecated Use $instanceProperties or $staticProperties instead
84+ */
8285 private array $ properties = [];
8386
87+ /** @var ExtendedPropertyReflection[] */
88+ private array $ instanceProperties = [];
89+
90+ /** @var ExtendedPropertyReflection[] */
91+ private array $ staticProperties = [];
92+
8493 /** @var RealClassClassConstantReflection[] */
8594 private array $ constants = [];
8695
@@ -147,6 +156,12 @@ final class ClassReflection
147156 /** @var array<string, bool> */
148157 private array $ hasPropertyCache = [];
149158
159+ /** @var array<string, bool> */
160+ private array $ hasInstancePropertyCache = [];
161+
162+ /** @var array<string, bool> */
163+ private array $ hasStaticPropertyCache = [];
164+
150165 /**
151166 * @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions
152167 * @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions
@@ -460,6 +475,9 @@ private function allowsDynamicPropertiesExtensions(): bool
460475 return false ;
461476 }
462477
478+ /**
479+ * @deprecated Use hasInstanceProperty or hasStaticProperty instead
480+ */
463481 public function hasProperty (string $ propertyName ): bool
464482 {
465483 if (array_key_exists ($ propertyName , $ this ->hasPropertyCache )) {
@@ -479,13 +497,61 @@ public function hasProperty(string $propertyName): bool
479497 }
480498 }
481499
500+ // For BC purpose
501+ if ($ this ->getPhpExtension ()->hasStaticProperty ($ this , $ propertyName )) {
502+ return $ this ->hasPropertyCache [$ propertyName ] = true ;
503+ }
504+
482505 if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasProperty ($ this , $ propertyName )) {
483506 return $ this ->hasPropertyCache [$ propertyName ] = true ;
484507 }
485508
486509 return $ this ->hasPropertyCache [$ propertyName ] = false ;
487510 }
488511
512+ public function hasInstanceProperty (string $ propertyName ): bool
513+ {
514+ if (array_key_exists ($ propertyName , $ this ->hasInstancePropertyCache )) {
515+ return $ this ->hasInstancePropertyCache [$ propertyName ];
516+ }
517+
518+ if ($ this ->isEnum ()) {
519+ return $ this ->hasInstancePropertyCache [$ propertyName ] = $ this ->hasNativeProperty ($ propertyName );
520+ }
521+
522+ foreach ($ this ->propertiesClassReflectionExtensions as $ i => $ extension ) {
523+ if ($ i > 0 && !$ this ->allowsDynamicPropertiesExtensions ()) {
524+ break ;
525+ }
526+ if ($ extension ->hasProperty ($ this , $ propertyName )) {
527+ return $ this ->hasInstancePropertyCache [$ propertyName ] = true ;
528+ }
529+ }
530+
531+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasInstanceProperty ($ this , $ propertyName )) {
532+ return $ this ->hasPropertyCache [$ propertyName ] = true ;
533+ }
534+
535+ return $ this ->hasPropertyCache [$ propertyName ] = false ;
536+ }
537+
538+ public function hasStaticProperty (string $ propertyName ): bool
539+ {
540+ if (array_key_exists ($ propertyName , $ this ->hasStaticPropertyCache )) {
541+ return $ this ->hasStaticPropertyCache [$ propertyName ];
542+ }
543+
544+ if ($ this ->getPhpExtension ()->hasStaticProperty ($ this , $ propertyName )) {
545+ return $ this ->hasStaticPropertyCache [$ propertyName ] = true ;
546+ }
547+
548+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasStaticProperty ($ this , $ propertyName )) {
549+ return $ this ->hasStaticPropertyCache [$ propertyName ] = true ;
550+ }
551+
552+ return $ this ->hasStaticPropertyCache [$ propertyName ] = false ;
553+ }
554+
489555 public function hasMethod (string $ methodName ): bool
490556 {
491557 if (array_key_exists ($ methodName , $ this ->hasMethodCache )) {
@@ -630,6 +696,20 @@ public function evictPrivateSymbols(): void
630696
631697 unset($ this ->properties [$ name ]);
632698 }
699+ foreach ($ this ->instanceProperties as $ name => $ property ) {
700+ if (!$ property ->isPrivate ()) {
701+ continue ;
702+ }
703+
704+ unset($ this ->instanceProperties [$ name ]);
705+ }
706+ foreach ($ this ->staticProperties as $ name => $ property ) {
707+ if (!$ property ->isPrivate ()) {
708+ continue ;
709+ }
710+
711+ unset($ this ->staticProperties [$ name ]);
712+ }
633713 foreach ($ this ->methods as $ name => $ method ) {
634714 if (!$ method ->isPrivate ()) {
635715 continue ;
@@ -640,6 +720,7 @@ public function evictPrivateSymbols(): void
640720 $ this ->getPhpExtension ()->evictPrivateSymbols ($ this ->getCacheKey ());
641721 }
642722
723+ /** @deprecated Use getInstanceProperty or getStaticProperty */
643724 public function getProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
644725 {
645726 if ($ this ->isEnum ()) {
@@ -669,6 +750,15 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
669750 }
670751 }
671752
753+ // For BC purpose
754+ if ($ this ->getPhpExtension ()->hasStaticProperty ($ this , $ propertyName )) {
755+ $ property = $ this ->wrapExtendedProperty ($ this ->getPhpExtension ()->getStaticProperty ($ this , $ propertyName ));
756+ if ($ scope ->canReadProperty ($ property )) {
757+ return $ this ->properties [$ key ] = $ property ;
758+ }
759+ $ this ->properties [$ key ] = $ property ;
760+ }
761+
672762 if (!isset ($ this ->properties [$ key ])) {
673763 if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasProperty ($ this , $ propertyName )) {
674764 $ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getProperty ($ this , $ propertyName );
@@ -683,6 +773,80 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
683773 return $ this ->properties [$ key ];
684774 }
685775
776+ public function getInstanceProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
777+ {
778+ if ($ this ->isEnum ()) {
779+ return $ this ->getNativeProperty ($ propertyName );
780+ }
781+
782+ $ key = $ propertyName ;
783+ if ($ scope ->isInClass ()) {
784+ $ key = sprintf ('%s-%s ' , $ key , $ scope ->getClassReflection ()->getCacheKey ());
785+ }
786+
787+ if (!isset ($ this ->instanceProperties [$ key ])) {
788+ foreach ($ this ->propertiesClassReflectionExtensions as $ i => $ extension ) {
789+ if ($ i > 0 && !$ this ->allowsDynamicPropertiesExtensions ()) {
790+ break ;
791+ }
792+
793+ if (!$ extension ->hasProperty ($ this , $ propertyName )) {
794+ continue ;
795+ }
796+
797+ $ property = $ this ->wrapExtendedProperty ($ extension ->getProperty ($ this , $ propertyName ));
798+ if ($ scope ->canReadProperty ($ property )) {
799+ return $ this ->instanceProperties [$ key ] = $ property ;
800+ }
801+ $ this ->instanceProperties [$ key ] = $ property ;
802+ }
803+ }
804+
805+ if (!isset ($ this ->instanceProperties [$ key ])) {
806+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasInstanceProperty ($ this , $ propertyName )) {
807+ $ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getInstanceProperty ($ this , $ propertyName );
808+ $ this ->instanceProperties [$ key ] = $ property ;
809+ }
810+ }
811+
812+ if (!isset ($ this ->instanceProperties [$ key ])) {
813+ throw new MissingPropertyFromReflectionException ($ this ->getName (), $ propertyName );
814+ }
815+
816+ return $ this ->instanceProperties [$ key ];
817+ }
818+
819+ public function getStaticProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
820+ {
821+ $ key = $ propertyName ;
822+ if ($ scope ->isInClass ()) {
823+ $ key = sprintf ('%s-%s ' , $ key , $ scope ->getClassReflection ()->getCacheKey ());
824+ }
825+
826+ if (!isset ($ this ->staticProperties [$ key ])) {
827+ if ($ this ->getPhpExtension ()->hasStaticProperty ($ this , $ propertyName )) {
828+ $ property = $ this ->wrapExtendedProperty ($ this ->getPhpExtension ()->getStaticProperty ($ this , $ propertyName ));
829+ if ($ scope ->canReadProperty ($ property )) {
830+ return $ this ->staticProperties [$ key ] = $ property ;
831+ }
832+ $ this ->staticProperties [$ key ] = $ property ;
833+ }
834+ }
835+
836+ if (!isset ($ this ->staticProperties [$ key ])) {
837+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasStaticProperty ($ this , $ propertyName )) {
838+ $ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getStaticProperty ($ this , $ propertyName );
839+ $ this ->staticProperties [$ key ] = $ property ;
840+ }
841+ }
842+
843+ if (!isset ($ this ->staticProperties [$ key ])) {
844+ throw new MissingPropertyFromReflectionException ($ this ->getName (), $ propertyName );
845+ }
846+
847+ return $ this ->staticProperties [$ key ];
848+ }
849+
686850 public function hasNativeProperty (string $ propertyName ): bool
687851 {
688852 return $ this ->getPhpExtension ()->hasProperty ($ this , $ propertyName );
0 commit comments