Skip to content

Commit 8029167

Browse files
WIP Instance vs Static properties
1 parent 5878035 commit 8029167

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
@@ -83,6 +83,12 @@ final class ClassReflection
8383
/** @var ExtendedPropertyReflection[] */
8484
private array $properties = [];
8585

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

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

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

478+
/**
479+
* @deprecated Use hasInstanceProperty or hasStaticProperty instead
480+
*/
466481
public function hasProperty(string $propertyName): bool
467482
{
468483
if (array_key_exists($propertyName, $this->hasPropertyCache)) {
@@ -482,13 +497,61 @@ public function hasProperty(string $propertyName): bool
482497
}
483498
}
484499

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

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

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+
492555
public function hasMethod(string $methodName): bool
493556
{
494557
if (array_key_exists($methodName, $this->hasMethodCache)) {
@@ -633,6 +696,20 @@ public function evictPrivateSymbols(): void
633696

634697
unset($this->properties[$name]);
635698
}
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+
}
636713
foreach ($this->methods as $name => $method) {
637714
if (!$method->isPrivate()) {
638715
continue;
@@ -643,6 +720,7 @@ public function evictPrivateSymbols(): void
643720
$this->getPhpExtension()->evictPrivateSymbols($this->getCacheKey());
644721
}
645722

723+
/** @deprecated Use getInstanceProperty or getStaticProperty */
646724
public function getProperty(string $propertyName, ClassMemberAccessAnswerer $scope): ExtendedPropertyReflection
647725
{
648726
if ($this->isEnum()) {
@@ -672,6 +750,15 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
672750
}
673751
}
674752

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+
675762
if (!isset($this->properties[$key])) {
676763
if ($this->requireExtendsPropertiesClassReflectionExtension->hasProperty($this, $propertyName)) {
677764
$property = $this->requireExtendsPropertiesClassReflectionExtension->getProperty($this, $propertyName);
@@ -686,9 +773,83 @@ public function getProperty(string $propertyName, ClassMemberAccessAnswerer $sco
686773
return $this->properties[$key];
687774
}
688775

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+
689850
public function hasNativeProperty(string $propertyName): bool
690851
{
691-
return $this->getPhpExtension()->hasProperty($this, $propertyName);
852+
return $this->getPhpExtension()->hasNativeProperty($this, $propertyName);
692853
}
693854

694855
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)