Skip to content

Commit 1edc9d3

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

File tree

3 files changed

+288
-10
lines changed

3 files changed

+288
-10
lines changed

src/Reflection/ClassReflection.php

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

@@ -147,6 +156,12 @@ final class ClassReflection
147156
/** @var array<string, bool> */
148157
private array $hasPropertyCache = [];
149158

159+
/** @var array<string, bool> */
160+
private array $hasInstancePropertyCache = [];
161+
162+
/** @var array<string, bool> */
163+
private array $hasStaticPropertyCache = [];
164+
150165
/**
151166
* @param PropertiesClassReflectionExtension[] $propertiesClassReflectionExtensions
152167
* @param MethodsClassReflectionExtension[] $methodsClassReflectionExtensions
@@ -460,6 +475,9 @@ private function allowsDynamicPropertiesExtensions(): bool
460475
return false;
461476
}
462477

478+
/**
479+
* @deprecated Use hasInstanceProperty or hasStaticProperty instead
480+
*/
463481
public function hasProperty(string $propertyName): bool
464482
{
465483
if (array_key_exists($propertyName, $this->hasPropertyCache)) {
@@ -479,13 +497,61 @@ public function hasProperty(string $propertyName): bool
479497
}
480498
}
481499

500+
// For BC purpose
501+
if ($this->getPhpExtension()->hasStaticProperty($this, $propertyName)) {
502+
return $this->hasPropertyCache[$propertyName] = true;
503+
}
504+
482505
if ($this->requireExtendsPropertiesClassReflectionExtension->hasProperty($this, $propertyName)) {
483506
return $this->hasPropertyCache[$propertyName] = true;
484507
}
485508

486509
return $this->hasPropertyCache[$propertyName] = false;
487510
}
488511

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

631697
unset($this->properties[$name]);
632698
}
699+
foreach ($this->instanceProperties as $name => $property) {
700+
if (!$property->isPrivate()) {
701+
continue;
702+
}
703+
704+
unset($this->instanceProperties[$name]);
705+
}
706+
foreach ($this->staticProperties as $name => $property) {
707+
if (!$property->isPrivate()) {
708+
continue;
709+
}
710+
711+
unset($this->staticProperties[$name]);
712+
}
633713
foreach ($this->methods as $name => $method) {
634714
if (!$method->isPrivate()) {
635715
continue;
@@ -640,6 +720,7 @@ public function evictPrivateSymbols(): void
640720
$this->getPhpExtension()->evictPrivateSymbols($this->getCacheKey());
641721
}
642722

723+
/** @deprecated Use getInstanceProperty or getStaticProperty */
643724
public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
644725
{
645726
if ($this->isEnum()) {
@@ -669,6 +750,15 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
669750
}
670751
}
671752

753+
// For BC purpose
754+
if ($this->getPhpExtension()->hasStaticProperty($this, $propertyName)) {
755+
$property = $this->wrapExtendedProperty($this->getPhpExtension()->getStaticProperty($this, $propertyName));
756+
if ($scope->canReadProperty($property)) {
757+
return $this->properties[$key] = $property;
758+
}
759+
$this->properties[$key] = $property;
760+
}
761+
672762
if (!isset($this->properties[$key])) {
673763
if ($this->requireExtendsPropertiesClassReflectionExtension->hasProperty($this, $propertyName)) {
674764
$property = $this->requireExtendsPropertiesClassReflectionExtension->getProperty($this, $propertyName);
@@ -683,6 +773,80 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
683773
return $this->properties[$key];
684774
}
685775

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

src/Reflection/Php/PhpClassReflectionExtension.php

Lines changed: 36 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,23 @@ 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+
169203
public function getNativeProperty(ClassReflection $classReflection, string $propertyName): PhpPropertyReflection
170204
{
171205
if (!isset($this->nativeProperties[$classReflection->getCacheKey()][$propertyName])) {
@@ -177,6 +211,7 @@ public function getNativeProperty(ClassReflection $classReflection, string $prop
177211
return $this->nativeProperties[$classReflection->getCacheKey()][$propertyName];
178212
}
179213

214+
// TODO: Find the difference between createInstanceProperty and createStaticProperty
180215
private function createProperty(
181216
ClassReflection $classReflection,
182217
string $propertyName,

0 commit comments

Comments
 (0)