Skip to content

Commit 3dd65e7

Browse files
WIP Instance vs Static properties
1 parent 8984ef9 commit 3dd65e7

File tree

6 files changed

+318
-14
lines changed

6 files changed

+318
-14
lines changed

src/Reflection/ClassReflection.php

Lines changed: 162 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ final class ClassReflection
8282
/** @var ExtendedPropertyReflection[] */
8383
private array $properties = [];
8484

85+
/** @var ExtendedPropertyReflection[] */
86+
private array $instanceProperties = [];
87+
88+
/** @var ExtendedPropertyReflection[] */
89+
private array $staticProperties = [];
90+
8591
/** @var RealClassClassConstantReflection[] */
8692
private array $constants = [];
8793

@@ -148,6 +154,12 @@ final class ClassReflection
148154
/** @var array<string, bool> */
149155
private array $hasPropertyCache = [];
150156

157+
/** @var array<string, bool> */
158+
private array $hasInstancePropertyCache = [];
159+
160+
/** @var array<string, bool> */
161+
private array $hasStaticPropertyCache = [];
162+
151163
/**
152164
* @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions
153165
* @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions
@@ -462,6 +474,9 @@ private function allowsDynamicPropertiesExtensions(): bool
462474
return false;
463475
}
464476

477+
/**
478+
* @deprecated Use hasInstanceProperty or hasStaticProperty instead
479+
*/
465480
public function hasProperty(string $propertyName): bool
466481
{
467482
if (array_key_exists($propertyName, $this->hasPropertyCache)) {
@@ -481,13 +496,61 @@ public function hasProperty(string $propertyName): bool
481496
}
482497
}
483498

499+
// For BC purpose
500+
if ($this->getPhpExtension()->hasStaticProperty($this, $propertyName)) {
501+
return $this->hasPropertyCache[$propertyName] = true;
502+
}
503+
484504
if ($this->requireExtendsPropertiesClassReflectionExtension->hasProperty($this, $propertyName)) {
485505
return $this->hasPropertyCache[$propertyName] = true;
486506
}
487507

488508
return $this->hasPropertyCache[$propertyName] = false;
489509
}
490510

511+
public function hasInstanceProperty(string $propertyName): bool
512+
{
513+
if (array_key_exists($propertyName, $this->hasInstancePropertyCache)) {
514+
return $this->hasInstancePropertyCache[$propertyName];
515+
}
516+
517+
if ($this->isEnum()) {
518+
return $this->hasInstancePropertyCache[$propertyName] = $this->hasNativeProperty($propertyName);
519+
}
520+
521+
foreach ($this->propertiesClassReflectionExtensions as $i => $extension) {
522+
if ($i > 0 && !$this->allowsDynamicPropertiesExtensions()) {
523+
break;
524+
}
525+
if ($extension->hasProperty($this, $propertyName)) {
526+
return $this->hasInstancePropertyCache[$propertyName] = true;
527+
}
528+
}
529+
530+
if ($this->requireExtendsPropertiesClassReflectionExtension->hasInstanceProperty($this, $propertyName)) {
531+
return $this->hasPropertyCache[$propertyName] = true;
532+
}
533+
534+
return $this->hasPropertyCache[$propertyName] = false;
535+
}
536+
537+
public function hasStaticProperty(string $propertyName): bool
538+
{
539+
if (array_key_exists($propertyName, $this->hasStaticPropertyCache)) {
540+
return $this->hasStaticPropertyCache[$propertyName];
541+
}
542+
543+
if ($this->getPhpExtension()->hasStaticProperty($this, $propertyName)) {
544+
return $this->hasStaticPropertyCache[$propertyName] = true;
545+
}
546+
547+
if ($this->requireExtendsPropertiesClassReflectionExtension->hasStaticProperty($this, $propertyName)) {
548+
return $this->hasStaticPropertyCache[$propertyName] = true;
549+
}
550+
551+
return $this->hasStaticPropertyCache[$propertyName] = false;
552+
}
553+
491554
public function hasMethod(string $methodName): bool
492555
{
493556
if (array_key_exists($methodName, $this->hasMethodCache)) {
@@ -632,6 +695,20 @@ public function evictPrivateSymbols(): void
632695

633696
unset($this->properties[$name]);
634697
}
698+
foreach ($this->instanceProperties as $name => $property) {
699+
if (!$property->isPrivate()) {
700+
continue;
701+
}
702+
703+
unset($this->instanceProperties[$name]);
704+
}
705+
foreach ($this->staticProperties as $name => $property) {
706+
if (!$property->isPrivate()) {
707+
continue;
708+
}
709+
710+
unset($this->staticProperties[$name]);
711+
}
635712
foreach ($this->methods as $name => $method) {
636713
if (!$method->isPrivate()) {
637714
continue;
@@ -642,6 +719,7 @@ public function evictPrivateSymbols(): void
642719
$this->getPhpExtension()->evictPrivateSymbols($this->getCacheKey());
643720
}
644721

722+
/** @deprecated Use getInstanceProperty or getStaticProperty */
645723
public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
646724
{
647725
if ($this->isEnum()) {
@@ -671,6 +749,15 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
671749
}
672750
}
673751

752+
// For BC purpose
753+
if ($this->getPhpExtension()->hasStaticProperty($this, $propertyName)) {
754+
$property = $this->wrapExtendedProperty($this->getPhpExtension()->getStaticProperty($this, $propertyName));
755+
if ($scope->canReadProperty($property)) {
756+
return $this->properties[$key] = $property;
757+
}
758+
$this->properties[$key] = $property;
759+
}
760+
674761
if (!isset($this->properties[$key])) {
675762
if ($this->requireExtendsPropertiesClassReflectionExtension->hasProperty($this, $propertyName)) {
676763
$property = $this->requireExtendsPropertiesClassReflectionExtension->getProperty($this, $propertyName);
@@ -685,9 +772,83 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
685772
return $this->properties[$key];
686773
}
687774

775+
public function getInstanceProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
776+
{
777+
if ($this->isEnum()) {
778+
return $this->getNativeProperty($propertyName);
779+
}
780+
781+
$key = $propertyName;
782+
if ($scope->isInClass()) {
783+
$key = sprintf('%s-%s', $key, $scope->getClassReflection()->getCacheKey());
784+
}
785+
786+
if (!isset($this->instanceProperties[$key])) {
787+
foreach ($this->propertiesClassReflectionExtensions as $i => $extension) {
788+
if ($i > 0 && !$this->allowsDynamicPropertiesExtensions()) {
789+
break;
790+
}
791+
792+
if (!$extension->hasProperty($this, $propertyName)) {
793+
continue;
794+
}
795+
796+
$property = $this->wrapExtendedProperty($extension->getProperty($this, $propertyName));
797+
if ($scope->canReadProperty($property)) {
798+
return $this->instanceProperties[$key] = $property;
799+
}
800+
$this->instanceProperties[$key] = $property;
801+
}
802+
}
803+
804+
if (!isset($this->instanceProperties[$key])) {
805+
if ($this->requireExtendsPropertiesClassReflectionExtension->hasInstanceProperty($this, $propertyName)) {
806+
$property = $this->requireExtendsPropertiesClassReflectionExtension->getInstanceProperty($this, $propertyName);
807+
$this->instanceProperties[$key] = $property;
808+
}
809+
}
810+
811+
if (!isset($this->instanceProperties[$key])) {
812+
throw new MissingPropertyFromReflectionException($this->getName(), $propertyName);
813+
}
814+
815+
return $this->instanceProperties[$key];
816+
}
817+
818+
public function getStaticProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
819+
{
820+
$key = $propertyName;
821+
if ($scope->isInClass()) {
822+
$key = sprintf('%s-%s', $key, $scope->getClassReflection()->getCacheKey());
823+
}
824+
825+
if (!isset($this->staticProperties[$key])) {
826+
if ($this->getPhpExtension()->hasStaticProperty($this, $propertyName)) {
827+
$property = $this->wrapExtendedProperty($this->getPhpExtension()->getStaticProperty($this, $propertyName));
828+
if ($scope->canReadProperty($property)) {
829+
return $this->staticProperties[$key] = $property;
830+
}
831+
$this->staticProperties[$key] = $property;
832+
}
833+
}
834+
835+
if (!isset($this->staticProperties[$key])) {
836+
if ($this->requireExtendsPropertiesClassReflectionExtension->hasStaticProperty($this, $propertyName)) {
837+
$property = $this->requireExtendsPropertiesClassReflectionExtension->getStaticProperty($this, $propertyName);
838+
$this->staticProperties[$key] = $property;
839+
}
840+
}
841+
842+
if (!isset($this->staticProperties[$key])) {
843+
throw new MissingPropertyFromReflectionException($this->getName(), $propertyName);
844+
}
845+
846+
return $this->staticProperties[$key];
847+
}
848+
688849
public function hasNativeProperty(string $propertyName): bool
689850
{
690-
return $this->getPhpExtension()->hasProperty($this, $propertyName);
851+
return $this->getPhpExtension()->hasNativeProperty($this, $propertyName);
691852
}
692853

693854
public function getNativeProperty(string $propertyName): PhpPropertyReflection

src/Reflection/Php/PhpClassReflectionExtension.php

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ final class PhpClassReflectionExtension
7272
/** @var ExtendedPropertyReflection[][] */
7373
private array $propertiesIncludingAnnotations = [];
7474

75+
/** @var ExtendedPropertyReflection[][] */
76+
private array $staticPropertiesIncludingAnnotations = [];
77+
7578
/** @var PhpPropertyReflection[][] */
7679
private array $nativeProperties = [];
7780

@@ -119,6 +122,17 @@ public function evictPrivateSymbols(string $classCacheKey): void
119122
unset($this->propertiesIncludingAnnotations[$key][$name]);
120123
}
121124
}
125+
foreach ($this->staticPropertiesIncludingAnnotations as $key => $properties) {
126+
if ($key !== $classCacheKey) {
127+
continue;
128+
}
129+
foreach ($properties as $name => $property) {
130+
if (!$property->isPrivate()) {
131+
continue;
132+
}
133+
unset($this->staticPropertiesIncludingAnnotations[$key][$name]);
134+
}
135+
}
122136
foreach ($this->nativeProperties as $key => $properties) {
123137
if ($key !== $classCacheKey) {
124138
continue;
@@ -156,7 +170,10 @@ public function evictPrivateSymbols(string $classCacheKey): void
156170

157171
public function hasProperty(ClassReflection $classReflection, string $propertyName): bool
158172
{
159-
return $classReflection->getNativeReflection()->hasProperty($propertyName);
173+
$nativeReflection = $classReflection->getNativeReflection();
174+
175+
return $nativeReflection->hasProperty($propertyName)
176+
&& !$nativeReflection->getProperty($propertyName)->isStatic();
160177
}
161178

162179
public function getProperty(ClassReflection $classReflection, string $propertyName): ExtendedPropertyReflection
@@ -168,6 +185,28 @@ public function getProperty(ClassReflection $classReflection, string $propertyNa
168185
return $this->propertiesIncludingAnnotations[$classReflection->getCacheKey()][$propertyName];
169186
}
170187

188+
public function hasStaticProperty(ClassReflection $classReflection, string $propertyName): bool
189+
{
190+
$nativeReflection = $classReflection->getNativeReflection();
191+
192+
return $nativeReflection->hasProperty($propertyName)
193+
&& $nativeReflection->getProperty($propertyName)->isStatic();
194+
}
195+
196+
public function getStaticProperty(ClassReflection $classReflection, string $propertyName): ExtendedPropertyReflection
197+
{
198+
if (!isset($this->staticPropertiesIncludingAnnotations[$classReflection->getCacheKey()][$propertyName])) {
199+
$this->staticPropertiesIncludingAnnotations[$classReflection->getCacheKey()][$propertyName] = $this->createProperty($classReflection, $propertyName, true);
200+
}
201+
202+
return $this->staticPropertiesIncludingAnnotations[$classReflection->getCacheKey()][$propertyName];
203+
}
204+
205+
public function hasNativeProperty(ClassReflection $classReflection, string $propertyName): bool
206+
{
207+
return $classReflection->getNativeReflection()->hasProperty($propertyName);
208+
}
209+
171210
public function getNativeProperty(ClassReflection $classReflection, string $propertyName): PhpPropertyReflection
172211
{
173212
if (!isset($this->nativeProperties[$classReflection->getCacheKey()][$propertyName])) {
@@ -179,6 +218,7 @@ public function getNativeProperty(ClassReflection $classReflection, string $prop
179218
return $this->nativeProperties[$classReflection->getCacheKey()][$propertyName];
180219
}
181220

221+
// TODO: Find the difference between createInstanceProperty and createStaticProperty
182222
private function createProperty(
183223
ClassReflection $classReflection,
184224
string $propertyName,

0 commit comments

Comments
 (0)