@@ -83,6 +83,12 @@ final class ClassReflection
83
83
/** @var ExtendedPropertyReflection[] */
84
84
private array $ properties = [];
85
85
86
+ /** @var ExtendedPropertyReflection[] */
87
+ private array $ instanceProperties = [];
88
+
89
+ /** @var ExtendedPropertyReflection[] */
90
+ private array $ staticProperties = [];
91
+
86
92
/** @var RealClassClassConstantReflection[] */
87
93
private array $ constants = [];
88
94
@@ -149,6 +155,12 @@ final class ClassReflection
149
155
/** @var array<string, bool> */
150
156
private array $ hasPropertyCache = [];
151
157
158
+ /** @var array<string, bool> */
159
+ private array $ hasInstancePropertyCache = [];
160
+
161
+ /** @var array<string, bool> */
162
+ private array $ hasStaticPropertyCache = [];
163
+
152
164
/**
153
165
* @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions
154
166
* @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions
@@ -449,6 +461,9 @@ public function allowsDynamicProperties(): bool
449
461
return $ attributes !== [];
450
462
}
451
463
464
+ /**
465
+ * @deprecated Use hasInstanceProperty or hasStaticProperty instead
466
+ */
452
467
public function hasProperty (string $ propertyName ): bool
453
468
{
454
469
if (array_key_exists ($ propertyName , $ this ->hasPropertyCache )) {
@@ -468,13 +483,68 @@ public function hasProperty(string $propertyName): bool
468
483
}
469
484
}
470
485
486
+ // For BC purpose
487
+ if ($ this ->getPhpExtension ()->hasProperty ($ this , $ propertyName )) {
488
+ return $ this ->hasPropertyCache [$ propertyName ] = true ;
489
+ }
490
+
471
491
if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasProperty ($ this , $ propertyName )) {
472
492
return $ this ->hasPropertyCache [$ propertyName ] = true ;
473
493
}
474
494
475
495
return $ this ->hasPropertyCache [$ propertyName ] = false ;
476
496
}
477
497
498
+ public function hasInstanceProperty (string $ propertyName ): bool
499
+ {
500
+ if (array_key_exists ($ propertyName , $ this ->hasInstancePropertyCache )) {
501
+ return $ this ->hasInstancePropertyCache [$ propertyName ];
502
+ }
503
+
504
+ if ($ this ->isEnum ()) {
505
+ return $ this ->hasInstancePropertyCache [$ propertyName ] = $ this ->hasNativeProperty ($ propertyName );
506
+ }
507
+
508
+ foreach ($ this ->propertiesClassReflectionExtensions as $ i => $ extension ) {
509
+ if ($ i > 0 && !$ this ->allowsDynamicProperties ()) {
510
+ break ;
511
+ }
512
+ if ($ extension ->hasProperty ($ this , $ propertyName )) {
513
+ $ property = $ extension ->getProperty ($ this , $ propertyName );
514
+ if ($ property ->isStatic ()) {
515
+ continue ;
516
+ }
517
+ return $ this ->hasInstancePropertyCache [$ propertyName ] = true ;
518
+ }
519
+ }
520
+
521
+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasInstanceProperty ($ this , $ propertyName )) {
522
+ return $ this ->hasPropertyCache [$ propertyName ] = true ;
523
+ }
524
+
525
+ return $ this ->hasPropertyCache [$ propertyName ] = false ;
526
+ }
527
+
528
+ public function hasStaticProperty (string $ propertyName ): bool
529
+ {
530
+ if (array_key_exists ($ propertyName , $ this ->hasStaticPropertyCache )) {
531
+ return $ this ->hasStaticPropertyCache [$ propertyName ];
532
+ }
533
+
534
+ if ($ this ->getPhpExtension ()->hasProperty ($ this , $ propertyName )) {
535
+ $ property = $ this ->getPhpExtension ()->getProperty ($ this , $ propertyName );
536
+ if ($ property ->isStatic ()) {
537
+ return $ this ->hasStaticPropertyCache [$ propertyName ] = true ;
538
+ }
539
+ }
540
+
541
+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasStaticProperty ($ this , $ propertyName )) {
542
+ return $ this ->hasStaticPropertyCache [$ propertyName ] = true ;
543
+ }
544
+
545
+ return $ this ->hasStaticPropertyCache [$ propertyName ] = false ;
546
+ }
547
+
478
548
public function hasMethod (string $ methodName ): bool
479
549
{
480
550
if (array_key_exists ($ methodName , $ this ->hasMethodCache )) {
@@ -619,6 +689,20 @@ public function evictPrivateSymbols(): void
619
689
620
690
unset($ this ->properties [$ name ]);
621
691
}
692
+ foreach ($ this ->instanceProperties as $ name => $ property ) {
693
+ if (!$ property ->isPrivate ()) {
694
+ continue ;
695
+ }
696
+
697
+ unset($ this ->instanceProperties [$ name ]);
698
+ }
699
+ foreach ($ this ->staticProperties as $ name => $ property ) {
700
+ if (!$ property ->isPrivate ()) {
701
+ continue ;
702
+ }
703
+
704
+ unset($ this ->staticProperties [$ name ]);
705
+ }
622
706
foreach ($ this ->methods as $ name => $ method ) {
623
707
if (!$ method ->isPrivate ()) {
624
708
continue ;
@@ -629,6 +713,7 @@ public function evictPrivateSymbols(): void
629
713
$ this ->getPhpExtension ()->evictPrivateSymbols ($ this ->getCacheKey ());
630
714
}
631
715
716
+ /** @deprecated Use getInstanceProperty or getStaticProperty */
632
717
public function getProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
633
718
{
634
719
if ($ this ->isEnum ()) {
@@ -658,6 +743,13 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
658
743
}
659
744
}
660
745
746
+ // For BC purpose
747
+ if ($ this ->getPhpExtension ()->hasProperty ($ this , $ propertyName )) {
748
+ $ property = $ this ->getPhpExtension ()->getProperty ($ this , $ propertyName );
749
+
750
+ return $ this ->properties [$ key ] = $ property ;
751
+ }
752
+
661
753
if (!isset ($ this ->properties [$ key ])) {
662
754
if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasProperty ($ this , $ propertyName )) {
663
755
$ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getProperty ($ this , $ propertyName );
@@ -672,6 +764,79 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
672
764
return $ this ->properties [$ key ];
673
765
}
674
766
767
+ public function getInstanceProperty (string $ propertyName , ClassMemberAccessAnswerer $ scope ): ExtendedPropertyReflection
768
+ {
769
+ if ($ this ->isEnum ()) {
770
+ return $ this ->getNativeProperty ($ propertyName );
771
+ }
772
+
773
+ $ key = $ propertyName ;
774
+ if ($ scope ->isInClass ()) {
775
+ $ key = sprintf ('%s-%s ' , $ key , $ scope ->getClassReflection ()->getCacheKey ());
776
+ }
777
+
778
+ if (!isset ($ this ->instanceProperties [$ key ])) {
779
+ foreach ($ this ->propertiesClassReflectionExtensions as $ i => $ extension ) {
780
+ if ($ i > 0 && !$ this ->allowsDynamicProperties ()) {
781
+ break ;
782
+ }
783
+
784
+ if (!$ extension ->hasProperty ($ this , $ propertyName )) {
785
+ continue ;
786
+ }
787
+
788
+ $ nakedProperty = $ extension ->getProperty ($ this , $ propertyName );
789
+ if ($ nakedProperty ->isStatic ()) {
790
+ continue ;
791
+ }
792
+
793
+ $ property = $ this ->wrapExtendedProperty ($ propertyName , $ nakedProperty );
794
+ if ($ scope ->canReadProperty ($ property )) {
795
+ return $ this ->instanceProperties [$ key ] = $ property ;
796
+ }
797
+ $ this ->instanceProperties [$ key ] = $ property ;
798
+ }
799
+ }
800
+
801
+ if (!isset ($ this ->instanceProperties [$ key ])) {
802
+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasInstanceProperty ($ this , $ propertyName )) {
803
+ $ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getInstanceProperty ($ this , $ propertyName );
804
+ $ this ->instanceProperties [$ key ] = $ property ;
805
+ }
806
+ }
807
+
808
+ if (!isset ($ this ->instanceProperties [$ key ])) {
809
+ throw new MissingPropertyFromReflectionException ($ this ->getName (), $ propertyName );
810
+ }
811
+
812
+ return $ this ->instanceProperties [$ key ];
813
+ }
814
+
815
+ public function getStaticProperty (string $ propertyName ): ExtendedPropertyReflection
816
+ {
817
+ $ key = $ propertyName ;
818
+ if (isset ($ this ->staticProperties [$ key ])) {
819
+ return $ this ->staticProperties [$ key ];
820
+ }
821
+
822
+ if ($ this ->getPhpExtension ()->hasProperty ($ this , $ propertyName )) {
823
+ $ nakedProperty = $ this ->getPhpExtension ()->getProperty ($ this , $ propertyName );
824
+ if ($ nakedProperty ->isStatic ()) {
825
+ $ property = $ this ->wrapExtendedProperty ($ propertyName , $ nakedProperty );
826
+ if ($ property ->isStatic ()) {
827
+ return $ this ->staticProperties [$ key ] = $ property ;
828
+ }
829
+ }
830
+ }
831
+
832
+ if ($ this ->requireExtendsPropertiesClassReflectionExtension ->hasStaticProperty ($ this , $ propertyName )) {
833
+ $ property = $ this ->requireExtendsPropertiesClassReflectionExtension ->getStaticProperty ($ this , $ propertyName );
834
+ return $ this ->staticProperties [$ key ] = $ property ;
835
+ }
836
+
837
+ throw new MissingPropertyFromReflectionException ($ this ->getName (), $ propertyName );
838
+ }
839
+
675
840
public function hasNativeProperty (string $ propertyName ): bool
676
841
{
677
842
return $ this ->getPhpExtension ()->hasProperty ($ this , $ propertyName );
0 commit comments