@@ -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
@@ -144,9 +153,18 @@ final class ClassReflection
144153 /** @var array<string, bool> */
145154 private array $ hasMethodCache = [];
146155
147- /** @var array<string, bool> */
156+ /**
157+ * @var array<string, bool>
158+ * @deprecated Use $hasInstancePropertyCache or $hasStaticPropertyCache instead
159+ */
148160 private array $ hasPropertyCache = [];
149161
162+ /** @var array<string, bool> */
163+ private array $ hasInstancePropertyCache = [];
164+
165+ /** @var array<string, bool> */
166+ private array $ hasStaticPropertyCache = [];
167+
150168 /**
151169 * @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions
152170 * @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions
@@ -460,6 +478,9 @@ private function allowsDynamicPropertiesExtensions(): bool
460478 return false ;
461479 }
462480
481+ /**
482+ * @deprecated Use hasInstanceProperty or hasStaticProperty instead
483+ */
463484 public function hasProperty (string $ propertyName ): bool
464485 {
465486 if (array_key_exists ($ propertyName , $ this ->hasPropertyCache )) {
@@ -479,13 +500,61 @@ public function hasProperty(string $propertyName): bool
479500 }
480501 }
481502
503+ // For BC purpose
504+ if ($ this ->getPhpExtension ()->hasStaticProperty ($ this , $ propertyName )) {
505+ return $ this ->hasPropertyCache [$ propertyName ] = true ;
506+ }
507+
482508 if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasProperty ($ this , $ propertyName )) {
483509 return $ this ->hasPropertyCache [$ propertyName ] = true ;
484510 }
485511
486512 return $ this ->hasPropertyCache [$ propertyName ] = false ;
487513 }
488514
515+ public function hasInstanceProperty (string $ propertyName ): bool
516+ {
517+ if (array_key_exists ($ propertyName , $ this ->hasInstancePropertyCache )) {
518+ return $ this ->hasInstancePropertyCache [$ propertyName ];
519+ }
520+
521+ if ($ this ->isEnum ()) {
522+ return $ this ->hasInstancePropertyCache [$ propertyName ] = $ this ->hasNativeProperty ($ propertyName );
523+ }
524+
525+ foreach ($ this ->propertiesClassReflectionExtensions as $ i => $ extension ) {
526+ if ($ i > 0 && !$ this ->allowsDynamicPropertiesExtensions ()) {
527+ break ;
528+ }
529+ if ($ extension ->hasProperty ($ this , $ propertyName )) {
530+ return $ this ->hasInstancePropertyCache [$ propertyName ] = true ;
531+ }
532+ }
533+
534+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasInstanceProperty ($ this , $ propertyName )) {
535+ return $ this ->hasPropertyCache [$ propertyName ] = true ;
536+ }
537+
538+ return $ this ->hasPropertyCache [$ propertyName ] = false ;
539+ }
540+
541+ public function hasStaticProperty (string $ propertyName ): bool
542+ {
543+ if (array_key_exists ($ propertyName , $ this ->hasStaticPropertyCache )) {
544+ return $ this ->hasStaticPropertyCache [$ propertyName ];
545+ }
546+
547+ if ($ this ->getPhpExtension ()->hasStaticProperty ($ this , $ propertyName )) {
548+ return $ this ->hasStaticPropertyCache [$ propertyName ] = true ;
549+ }
550+
551+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasStaticProperty ($ this , $ propertyName )) {
552+ return $ this ->hasStaticPropertyCache [$ propertyName ] = true ;
553+ }
554+
555+ return $ this ->hasStaticPropertyCache [$ propertyName ] = false ;
556+ }
557+
489558 public function hasMethod (string $ methodName ): bool
490559 {
491560 if (array_key_exists ($ methodName , $ this ->hasMethodCache )) {
@@ -630,6 +699,20 @@ public function evictPrivateSymbols(): void
630699
631700 unset($ this ->properties [$ name ]);
632701 }
702+ foreach ($ this ->instanceProperties as $ name => $ property ) {
703+ if (!$ property ->isPrivate ()) {
704+ continue ;
705+ }
706+
707+ unset($ this ->instanceProperties [$ name ]);
708+ }
709+ foreach ($ this ->staticProperties as $ name => $ property ) {
710+ if (!$ property ->isPrivate ()) {
711+ continue ;
712+ }
713+
714+ unset($ this ->staticProperties [$ name ]);
715+ }
633716 foreach ($ this ->methods as $ name => $ method ) {
634717 if (!$ method ->isPrivate ()) {
635718 continue ;
@@ -640,6 +723,7 @@ public function evictPrivateSymbols(): void
640723 $ this ->getPhpExtension ()->evictPrivateSymbols ($ this ->getCacheKey ());
641724 }
642725
726+ /** @deprecated Use getInstanceProperty or getStaticProperty */
643727 public function getProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
644728 {
645729 if ($ this ->isEnum ()) {
@@ -669,6 +753,15 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
669753 }
670754 }
671755
756+ // For BC purpose
757+ if ($ this ->getPhpExtension ()->hasStaticProperty ($ this , $ propertyName )) {
758+ $ property = $ this ->wrapExtendedProperty ($ this ->getPhpExtension ()->getStaticProperty ($ this , $ propertyName ));
759+ if ($ scope ->canReadProperty ($ property )) {
760+ return $ this ->properties [$ key ] = $ property ;
761+ }
762+ $ this ->properties [$ key ] = $ property ;
763+ }
764+
672765 if (!isset ($ this ->properties [$ key ])) {
673766 if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasProperty ($ this , $ propertyName )) {
674767 $ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getProperty ($ this , $ propertyName );
@@ -683,9 +776,83 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
683776 return $ this ->properties [$ key ];
684777 }
685778
779+ public function getInstanceProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
780+ {
781+ if ($ this ->isEnum ()) {
782+ return $ this ->getNativeProperty ($ propertyName );
783+ }
784+
785+ $ key = $ propertyName ;
786+ if ($ scope ->isInClass ()) {
787+ $ key = sprintf ('%s-%s ' , $ key , $ scope ->getClassReflection ()->getCacheKey ());
788+ }
789+
790+ if (!isset ($ this ->instanceProperties [$ key ])) {
791+ foreach ($ this ->propertiesClassReflectionExtensions as $ i => $ extension ) {
792+ if ($ i > 0 && !$ this ->allowsDynamicPropertiesExtensions ()) {
793+ break ;
794+ }
795+
796+ if (!$ extension ->hasProperty ($ this , $ propertyName )) {
797+ continue ;
798+ }
799+
800+ $ property = $ this ->wrapExtendedProperty ($ extension ->getProperty ($ this , $ propertyName ));
801+ if ($ scope ->canReadProperty ($ property )) {
802+ return $ this ->instanceProperties [$ key ] = $ property ;
803+ }
804+ $ this ->instanceProperties [$ key ] = $ property ;
805+ }
806+ }
807+
808+ if (!isset ($ this ->instanceProperties [$ key ])) {
809+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasInstanceProperty ($ this , $ propertyName )) {
810+ $ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getInstanceProperty ($ this , $ propertyName );
811+ $ this ->instanceProperties [$ key ] = $ property ;
812+ }
813+ }
814+
815+ if (!isset ($ this ->instanceProperties [$ key ])) {
816+ throw new MissingPropertyFromReflectionException ($ this ->getName (), $ propertyName );
817+ }
818+
819+ return $ this ->instanceProperties [$ key ];
820+ }
821+
822+ public function getStaticProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
823+ {
824+ $ key = $ propertyName ;
825+ if ($ scope ->isInClass ()) {
826+ $ key = sprintf ('%s-%s ' , $ key , $ scope ->getClassReflection ()->getCacheKey ());
827+ }
828+
829+ if (!isset ($ this ->staticProperties [$ key ])) {
830+ if ($ this ->getPhpExtension ()->hasStaticProperty ($ this , $ propertyName )) {
831+ $ property = $ this ->wrapExtendedProperty ($ this ->getPhpExtension ()->getStaticProperty ($ this , $ propertyName ));
832+ if ($ scope ->canReadProperty ($ property )) {
833+ return $ this ->staticProperties [$ key ] = $ property ;
834+ }
835+ $ this ->staticProperties [$ key ] = $ property ;
836+ }
837+ }
838+
839+ if (!isset ($ this ->staticProperties [$ key ])) {
840+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasStaticProperty ($ this , $ propertyName )) {
841+ $ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getStaticProperty ($ this , $ propertyName );
842+ $ this ->staticProperties [$ key ] = $ property ;
843+ }
844+ }
845+
846+ if (!isset ($ this ->staticProperties [$ key ])) {
847+ throw new MissingPropertyFromReflectionException ($ this ->getName (), $ propertyName );
848+ }
849+
850+ return $ this ->staticProperties [$ key ];
851+ }
852+
686853 public function hasNativeProperty (string $ propertyName ): bool
687854 {
688- return $ this ->getPhpExtension ()->hasProperty ($ this , $ propertyName );
855+ return $ this ->getPhpExtension ()->hasNativeProperty ($ this , $ propertyName );
689856 }
690857
691858 public function getNativeProperty (string $ propertyName ): PhpPropertyReflection
0 commit comments