Skip to content

Commit 0edde2b

Browse files
WIP Instance vs Static properties
1 parent c5cf14b commit 0edde2b

6 files changed

+318
-14
lines changed

src/Reflection/ClassReflection.php

+162-1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ final class ClassReflection
8181
/** @var ExtendedPropertyReflection[] */
8282
private array $properties = [];
8383

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

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

156+
/** @var array<string, bool> */
157+
private array $hasInstancePropertyCache = [];
158+
159+
/** @var array<string, bool> */
160+
private array $hasStaticPropertyCache = [];
161+
150162
/**
151163
* @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions
152164
* @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions
@@ -460,6 +472,9 @@ private function allowsDynamicPropertiesExtensions(): bool
460472
return false;
461473
}
462474

475+
/**
476+
* @deprecated Use hasInstanceProperty or hasStaticProperty instead
477+
*/
463478
public function hasProperty(string $propertyName): bool
464479
{
465480
if (array_key_exists($propertyName, $this->hasPropertyCache)) {
@@ -479,13 +494,61 @@ public function hasProperty(string $propertyName): bool
479494
}
480495
}
481496

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

486506
return $this->hasPropertyCache[$propertyName] = false;
487507
}
488508

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

631694
unset($this->properties[$name]);
632695
}
696+
foreach ($this->instanceProperties as $name => $property) {
697+
if (!$property->isPrivate()) {
698+
continue;
699+
}
700+
701+
unset($this->instanceProperties[$name]);
702+
}
703+
foreach ($this->staticProperties as $name => $property) {
704+
if (!$property->isPrivate()) {
705+
continue;
706+
}
707+
708+
unset($this->staticProperties[$name]);
709+
}
633710
foreach ($this->methods as $name => $method) {
634711
if (!$method->isPrivate()) {
635712
continue;
@@ -640,6 +717,7 @@ public function evictPrivateSymbols(): void
640717
$this->getPhpExtension()->evictPrivateSymbols($this->getCacheKey());
641718
}
642719

720+
/** @deprecated Use getInstanceProperty or getStaticProperty */
643721
public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
644722
{
645723
if ($this->isEnum()) {
@@ -669,6 +747,15 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
669747
}
670748
}
671749

750+
// For BC purpose
751+
if ($this->getPhpExtension()->hasStaticProperty($this, $propertyName)) {
752+
$property = $this->wrapExtendedProperty($this->getPhpExtension()->getStaticProperty($this, $propertyName));
753+
if ($scope->canReadProperty($property)) {
754+
return $this->properties[$key] = $property;
755+
}
756+
$this->properties[$key] = $property;
757+
}
758+
672759
if (!isset($this->properties[$key])) {
673760
if ($this->requireExtendsPropertiesClassReflectionExtension->hasProperty($this, $propertyName)) {
674761
$property = $this->requireExtendsPropertiesClassReflectionExtension->getProperty($this, $propertyName);
@@ -683,9 +770,83 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
683770
return $this->properties[$key];
684771
}
685772

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

691852
public function getNativeProperty(string $propertyName): PhpPropertyReflection

src/Reflection/Php/PhpClassReflectionExtension.php

+41-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ final class PhpClassReflectionExtension
7171
/** @var ExtendedPropertyReflection[][] */
7272
private array $propertiesIncludingAnnotations = [];
7373

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

@@ -117,6 +120,17 @@ public function evictPrivateSymbols(string $classCacheKey): void
117120
unset($this->propertiesIncludingAnnotations[$key][$name]);
118121
}
119122
}
123+
foreach ($this->staticPropertiesIncludingAnnotations as $key => $properties) {
124+
if ($key !== $classCacheKey) {
125+
continue;
126+
}
127+
foreach ($properties as $name => $property) {
128+
if (!$property->isPrivate()) {
129+
continue;
130+
}
131+
unset($this->staticPropertiesIncludingAnnotations[$key][$name]);
132+
}
133+
}
120134
foreach ($this->nativeProperties as $key => $properties) {
121135
if ($key !== $classCacheKey) {
122136
continue;
@@ -154,7 +168,10 @@ public function evictPrivateSymbols(string $classCacheKey): void
154168

155169
public function hasProperty(ClassReflection $classReflection, string $propertyName): bool
156170
{
157-
return $classReflection->getNativeReflection()->hasProperty($propertyName);
171+
$nativeReflection = $classReflection->getNativeReflection();
172+
173+
return $nativeReflection->hasProperty($propertyName)
174+
&& !$nativeReflection->getProperty($propertyName)->isStatic();
158175
}
159176

160177
public function getProperty(ClassReflection $classReflection, string $propertyName): ExtendedPropertyReflection
@@ -166,6 +183,28 @@ public function getProperty(ClassReflection $classReflection, string $propertyNa
166183
return $this->propertiesIncludingAnnotations[$classReflection->getCacheKey()][$propertyName];
167184
}
168185

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

219+
// TODO: Find the difference between createInstanceProperty and createStaticProperty
180220
private function createProperty(
181221
ClassReflection $classReflection,
182222
string $propertyName,

0 commit comments

Comments
 (0)