diff --git a/composer.json b/composer.json index 384df3c..7b86c6b 100644 --- a/composer.json +++ b/composer.json @@ -19,6 +19,7 @@ "autoload": { "psr-4": { "gapple\\StructuredFields\\": "src/", + "gapple\\StructuredFields\\PHPStan\\": "phpstan-extension/src/", "gapple\\Tests\\StructuredFields\\": "tests/" } }, diff --git a/phpstan-extension/src/DynamicPropertiesClassReflectionExtension.php b/phpstan-extension/src/DynamicPropertiesClassReflectionExtension.php new file mode 100644 index 0000000..3909bd3 --- /dev/null +++ b/phpstan-extension/src/DynamicPropertiesClassReflectionExtension.php @@ -0,0 +1,29 @@ +is(Dictionary::class) + || $classReflection->is(Parameters::class) + ) + && preg_match('/^[a-z*][a-z0-9.*_-]*$/', $propertyName); + } + + /** + * {@inheritdoc} + */ + public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection + { + return new DynamicPropertyReflection($classReflection); + } +} diff --git a/phpstan-extension/src/DynamicPropertyReflection.php b/phpstan-extension/src/DynamicPropertyReflection.php new file mode 100644 index 0000000..316b3f9 --- /dev/null +++ b/phpstan-extension/src/DynamicPropertyReflection.php @@ -0,0 +1,87 @@ +classReflection = $classReflection; + } + + public function getDeclaringClass(): \PHPStan\Reflection\ClassReflection + { + return $this->classReflection; + } + + public function isStatic(): bool + { + return false; + } + + public function isPrivate(): bool + { + return false; + } + + public function isPublic(): bool + { + return true; + } + + public function getDocComment(): ?string + { + return null; + } + + public function getReadableType(): Type + { + return new MixedType(); + } + + public function getWritableType(): Type + { + return new MixedType(); + } + + public function canChangeTypeAfterAssignment(): bool + { + return true; + } + + public function isReadable(): bool + { + return true; + } + + public function isWritable(): bool + { + return true; + } + + public function isDeprecated(): TrinaryLogic + { + return TrinaryLogic::createMaybe(); + } + + public function getDeprecatedDescription(): ?string + { + return null; + } + + public function isInternal(): TrinaryLogic + { + return TrinaryLogic::createMaybe(); + } +} diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 0cc958d..1a2a04f 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -8,10 +8,6 @@ parameters: - src - tests - universalObjectCratesClasses: - - gapple\StructuredFields\Dictionary - - gapple\StructuredFields\Parameters - featureToggles: readOnlyByPhpDoc: true @@ -19,3 +15,8 @@ parameters: - message: '#Unreachable statement - code above always terminates.#' path: src/TupleTrait.php + +services: + - class: gapple\StructuredFields\PHPStan\DynamicPropertiesClassReflectionExtension + tags: + - phpstan.broker.propertiesClassReflectionExtension