Skip to content

Commit 0657076

Browse files
WIP Instance vs Static properties
1 parent c5cf14b commit 0657076

File tree

3 files changed

+298
-12
lines changed

3 files changed

+298
-12
lines changed

src/Reflection/ClassReflection.php

Lines changed: 170 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

src/Reflection/Php/PhpClassReflectionExtension.php

Lines changed: 41 additions & 1 deletion
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)