From 3a3d9110a250c2bab42edeb07bca6e389940c3b7 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 17 Feb 2025 10:40:51 +0300 Subject: [PATCH 01/20] PHP 8.4 --- .github/workflows/build.yml | 2 +- .github/workflows/composer-require-checker.yml | 2 +- .github/workflows/rector.yml | 2 +- .github/workflows/static.yml | 2 +- .github/workflows/yiisoft-di.yml | 1 + .github/workflows/yiisoft-factory.yml | 1 + CHANGELOG.md | 2 +- composer.json | 17 +++++++++-------- psalm.xml | 6 ------ psalm80.xml | 6 ------ 10 files changed, 16 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f73a90..68496d9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,4 +30,4 @@ jobs: os: >- ['ubuntu-latest', 'windows-latest'] php: >- - ['8.0', '8.1', '8.2', '8.3'] + ['8.0', '8.1', '8.2', '8.3', '8.4'] diff --git a/.github/workflows/composer-require-checker.yml b/.github/workflows/composer-require-checker.yml index 4336665..41c7d90 100644 --- a/.github/workflows/composer-require-checker.yml +++ b/.github/workflows/composer-require-checker.yml @@ -32,4 +32,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.0', '8.1', '8.2', '8.3'] + ['8.0', '8.1', '8.2', '8.3', '8.4'] diff --git a/.github/workflows/rector.yml b/.github/workflows/rector.yml index 35411d0..b229445 100644 --- a/.github/workflows/rector.yml +++ b/.github/workflows/rector.yml @@ -20,4 +20,4 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.3'] + ['8.4'] diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index d2a03af..64b476e 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -30,7 +30,7 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.1', '8.2', '8.3'] + ['8.1', '8.2', '8.3', '8.4'] psalm80: uses: yiisoft/actions/.github/workflows/psalm.yml@master with: diff --git a/.github/workflows/yiisoft-di.yml b/.github/workflows/yiisoft-di.yml index 5f1bdfb..5285df3 100644 --- a/.github/workflows/yiisoft-di.yml +++ b/.github/workflows/yiisoft-di.yml @@ -37,6 +37,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" steps: - name: Checkout Yii Definitions diff --git a/.github/workflows/yiisoft-factory.yml b/.github/workflows/yiisoft-factory.yml index 5a0b40c..f75fff3 100644 --- a/.github/workflows/yiisoft-factory.yml +++ b/.github/workflows/yiisoft-factory.yml @@ -37,6 +37,7 @@ jobs: - "8.1" - "8.2" - "8.3" + - "8.4" steps: - name: Checkout Yii Definitions diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d5834a..4cbdd46 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 3.3.2 under development -- no changes in this release. +- Chg #105: Change PHP constraint in `composer.json` to `~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0` (@vjik) ## 3.3.1 December 16, 2024 diff --git a/composer.json b/composer.json index 7e9e6f9..ecc82fa 100644 --- a/composer.json +++ b/composer.json @@ -26,16 +26,16 @@ } ], "require": { - "php": "^8.0", - "psr/container": "^1.0|^2.0" + "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/container": "^1.0 || ^2.0" }, "require-dev": { - "maglnet/composer-require-checker": "^4.2", - "phpunit/phpunit": "^9.5", - "rector/rector": "^1.0.0", - "roave/infection-static-analysis-plugin": "^1.18", - "spatie/phpunit-watcher": "^1.23", - "vimeo/psalm": "^4.30|^5.21", + "maglnet/composer-require-checker": "^4.4", + "phpunit/phpunit": "^9.6.22", + "rector/rector": "^1.2.10", + "roave/infection-static-analysis-plugin": "^1.25", + "spatie/phpunit-watcher": "^1.23.6", + "vimeo/psalm": "^4.30 || ^5.26.1 || ^6.6.1", "yiisoft/test-support": "^1.4" }, "autoload": { @@ -50,6 +50,7 @@ }, "config": { "sort-packages": true, + "bump-after-update": "dev", "allow-plugins": { "infection/extension-installer": true, "composer/package-versions-deprecated": true diff --git a/psalm.xml b/psalm.xml index 1e5dd14..b48c894 100644 --- a/psalm.xml +++ b/psalm.xml @@ -16,11 +16,5 @@ - - - - - - diff --git a/psalm80.xml b/psalm80.xml index 796ae44..d091d59 100644 --- a/psalm80.xml +++ b/psalm80.xml @@ -15,11 +15,5 @@ - - - - - - From 09a2f40ce5a98e794f77acaecc3923f64a81c4b6 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 17 Feb 2025 10:47:54 +0300 Subject: [PATCH 02/20] fix test --- tests/Unit/ParameterDefinitionTest.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/Unit/ParameterDefinitionTest.php b/tests/Unit/ParameterDefinitionTest.php index 6ddcc9f..580d214 100644 --- a/tests/Unit/ParameterDefinitionTest.php +++ b/tests/Unit/ParameterDefinitionTest.php @@ -177,8 +177,7 @@ public function testResolveNonTypedParameter(): void $this->expectException(NotInstantiableException::class); $this->expectExceptionMessage( 'Can not determine value of the "x" parameter without type when instantiating ' - . '"Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::Yiisoft\Definitions\Tests\Unit\{closure}()"' - . '. Please specify argument explicitly.' + . '"Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::' ); $definition->resolve($container); } @@ -195,8 +194,7 @@ public function testResolveBuiltinParameter(): void $this->expectException(NotInstantiableException::class); $this->expectExceptionMessage( 'Can not determine value of the "n" parameter of type "int" when instantiating ' - . '"Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::Yiisoft\Definitions\Tests\Unit\{closure}()".' - . ' Please specify argument explicitly.' + . '"Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::' ); $definition->resolve($container); } From 4bb9ae2bb7ff5c17dff43fe8c60792b259a1d8ae Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 17 Feb 2025 15:00:47 +0300 Subject: [PATCH 03/20] fix --- tests/Unit/ParameterDefinitionTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Unit/ParameterDefinitionTest.php b/tests/Unit/ParameterDefinitionTest.php index 580d214..63c9b10 100644 --- a/tests/Unit/ParameterDefinitionTest.php +++ b/tests/Unit/ParameterDefinitionTest.php @@ -179,6 +179,7 @@ public function testResolveNonTypedParameter(): void 'Can not determine value of the "x" parameter without type when instantiating ' . '"Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::' ); + $this->expectExceptionMessage('Please specify argument explicitly.'); $definition->resolve($container); } @@ -196,6 +197,7 @@ public function testResolveBuiltinParameter(): void 'Can not determine value of the "n" parameter of type "int" when instantiating ' . '"Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::' ); + $this->expectExceptionMessage('Please specify argument explicitly.'); $definition->resolve($container); } From cc2625cd2280238517f781370899ac0b069bcf62 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Mon, 17 Feb 2025 15:11:37 +0300 Subject: [PATCH 04/20] Use `Override` attribute --- composer.json | 2 +- src/ArrayDefinition.php | 2 ++ src/CallableDefinition.php | 2 ++ src/DynamicReference.php | 3 +++ src/ParameterDefinition.php | 2 ++ src/Reference.php | 3 +++ src/ValueDefinition.php | 2 ++ 7 files changed, 15 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ecc82fa..2cd92ab 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "rector/rector": "^1.2.10", "roave/infection-static-analysis-plugin": "^1.25", "spatie/phpunit-watcher": "^1.23.6", - "vimeo/psalm": "^4.30 || ^5.26.1 || ^6.6.1", + "vimeo/psalm": "^4.30 || ^5.26.1 || ^6.7.1", "yiisoft/test-support": "^1.4" }, "autoload": { diff --git a/src/ArrayDefinition.php b/src/ArrayDefinition.php index 20ed981..77bb322 100644 --- a/src/ArrayDefinition.php +++ b/src/ArrayDefinition.php @@ -5,6 +5,7 @@ namespace Yiisoft\Definitions; use InvalidArgumentException; +use Override; use Psr\Container\ContainerInterface; use ReflectionMethod; use Yiisoft\Definitions\Contract\DefinitionInterface; @@ -132,6 +133,7 @@ public function getMethodsAndProperties(): array return $this->methodsAndProperties; } + #[Override] public function resolve(ContainerInterface $container): object { $class = $this->class; diff --git a/src/CallableDefinition.php b/src/CallableDefinition.php index 6de1b00..56f42db 100644 --- a/src/CallableDefinition.php +++ b/src/CallableDefinition.php @@ -5,6 +5,7 @@ namespace Yiisoft\Definitions; use Closure; +use Override; use Psr\Container\ContainerInterface; use ReflectionException; use ReflectionFunction; @@ -41,6 +42,7 @@ public function __construct(array|callable $callable) $this->callable = $callable; } + #[Override] public function resolve(ContainerInterface $container): mixed { try { diff --git a/src/DynamicReference.php b/src/DynamicReference.php index 6806dc3..6ac0bee 100644 --- a/src/DynamicReference.php +++ b/src/DynamicReference.php @@ -4,6 +4,7 @@ namespace Yiisoft\Definitions; +use Override; use Psr\Container\ContainerInterface; use Yiisoft\Definitions\Contract\DefinitionInterface; use Yiisoft\Definitions\Contract\ReferenceInterface; @@ -51,11 +52,13 @@ private function __construct(mixed $definition) * * @throws InvalidConfigException If definition is not valid. */ + #[Override] public static function to(mixed $id): self { return new self($id); } + #[Override] public function resolve(ContainerInterface $container): mixed { return $this->definition->resolve($container); diff --git a/src/ParameterDefinition.php b/src/ParameterDefinition.php index e11fc05..682600c 100644 --- a/src/ParameterDefinition.php +++ b/src/ParameterDefinition.php @@ -4,6 +4,7 @@ namespace Yiisoft\Definitions; +use Override; use Psr\Container\ContainerInterface; use ReflectionNamedType; use ReflectionParameter; @@ -44,6 +45,7 @@ public function hasValue(): bool return $this->parameter->isDefaultValueAvailable(); } + #[Override] public function resolve(ContainerInterface $container): mixed { $type = $this->parameter->getType(); diff --git a/src/Reference.php b/src/Reference.php index fd58541..20a29eb 100644 --- a/src/Reference.php +++ b/src/Reference.php @@ -4,6 +4,7 @@ namespace Yiisoft\Definitions; +use Override; use Psr\Container\ContainerInterface; use Yiisoft\Definitions\Contract\ReferenceInterface; use Yiisoft\Definitions\Exception\InvalidConfigException; @@ -45,6 +46,7 @@ private function __construct(mixed $id, private bool $optional) /** * @throws InvalidConfigException If ID is not string. */ + #[Override] public static function to(mixed $id): self { return new self($id, false); @@ -62,6 +64,7 @@ public static function optional(mixed $id): self return new self($id, true); } + #[Override] public function resolve(ContainerInterface $container): mixed { return (!$this->optional || $container->has($this->id)) ? $container->get($this->id) : null; diff --git a/src/ValueDefinition.php b/src/ValueDefinition.php index 0a83f19..034cb3f 100644 --- a/src/ValueDefinition.php +++ b/src/ValueDefinition.php @@ -4,6 +4,7 @@ namespace Yiisoft\Definitions; +use Override; use Psr\Container\ContainerInterface; use Yiisoft\Definitions\Contract\DefinitionInterface; @@ -32,6 +33,7 @@ public function getType(): ?string return $this->type; } + #[Override] public function resolve(ContainerInterface $container): mixed { return $this->value; From 72701a39a1b1b74c472b26ee1ae29b5924416835 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 09:32:15 +0300 Subject: [PATCH 05/20] fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a5dacd..f35ec04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## 3.3.2 under development -- Chg #105: Change PHP constraint in `composer.json` to `~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0` (@vjik) +- Chg #105: Change PHP constraint in `composer.json` to `~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0` (@vjik) - Chg #106: Bump minimal required PHP version to 8.1 (@vjik) - Enh #106: Minor performance optimization: use FQN for PHP functions, remove unnecessary conditions (@vjik) - Enh #106: Mark readonly properties (@vjik) From beb055aee0cb31f0a8dd82af8dc8e3fb27c8e3c5 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 09:33:20 +0300 Subject: [PATCH 06/20] rm override --- src/ArrayDefinition.php | 2 -- src/CallableDefinition.php | 2 -- src/DynamicReference.php | 3 --- src/ParameterDefinition.php | 2 -- src/Reference.php | 3 --- src/ValueDefinition.php | 2 -- 6 files changed, 14 deletions(-) diff --git a/src/ArrayDefinition.php b/src/ArrayDefinition.php index 2c43fc0..fe410cf 100644 --- a/src/ArrayDefinition.php +++ b/src/ArrayDefinition.php @@ -5,7 +5,6 @@ namespace Yiisoft\Definitions; use InvalidArgumentException; -use Override; use Psr\Container\ContainerInterface; use ReflectionMethod; use Yiisoft\Definitions\Contract\DefinitionInterface; @@ -136,7 +135,6 @@ public function getMethodsAndProperties(): array return $this->methodsAndProperties; } - #[Override] public function resolve(ContainerInterface $container): object { $class = $this->class; diff --git a/src/CallableDefinition.php b/src/CallableDefinition.php index 56f42db..6de1b00 100644 --- a/src/CallableDefinition.php +++ b/src/CallableDefinition.php @@ -5,7 +5,6 @@ namespace Yiisoft\Definitions; use Closure; -use Override; use Psr\Container\ContainerInterface; use ReflectionException; use ReflectionFunction; @@ -42,7 +41,6 @@ public function __construct(array|callable $callable) $this->callable = $callable; } - #[Override] public function resolve(ContainerInterface $container): mixed { try { diff --git a/src/DynamicReference.php b/src/DynamicReference.php index 6ac0bee..6806dc3 100644 --- a/src/DynamicReference.php +++ b/src/DynamicReference.php @@ -4,7 +4,6 @@ namespace Yiisoft\Definitions; -use Override; use Psr\Container\ContainerInterface; use Yiisoft\Definitions\Contract\DefinitionInterface; use Yiisoft\Definitions\Contract\ReferenceInterface; @@ -52,13 +51,11 @@ private function __construct(mixed $definition) * * @throws InvalidConfigException If definition is not valid. */ - #[Override] public static function to(mixed $id): self { return new self($id); } - #[Override] public function resolve(ContainerInterface $container): mixed { return $this->definition->resolve($container); diff --git a/src/ParameterDefinition.php b/src/ParameterDefinition.php index a545546..9a7ba95 100644 --- a/src/ParameterDefinition.php +++ b/src/ParameterDefinition.php @@ -4,7 +4,6 @@ namespace Yiisoft\Definitions; -use Override; use Psr\Container\ContainerInterface; use ReflectionNamedType; use ReflectionParameter; @@ -47,7 +46,6 @@ public function hasValue(): bool return $this->parameter->isDefaultValueAvailable(); } - #[Override] public function resolve(ContainerInterface $container): mixed { $type = $this->parameter->getType(); diff --git a/src/Reference.php b/src/Reference.php index a0a366c..0af70ba 100644 --- a/src/Reference.php +++ b/src/Reference.php @@ -4,7 +4,6 @@ namespace Yiisoft\Definitions; -use Override; use Psr\Container\ContainerInterface; use Yiisoft\Definitions\Contract\ReferenceInterface; use Yiisoft\Definitions\Exception\InvalidConfigException; @@ -48,7 +47,6 @@ private function __construct( /** * @throws InvalidConfigException If ID is not string. */ - #[Override] public static function to(mixed $id): self { return new self($id, false); @@ -66,7 +64,6 @@ public static function optional(mixed $id): self return new self($id, true); } - #[Override] public function resolve(ContainerInterface $container): mixed { return (!$this->optional || $container->has($this->id)) ? $container->get($this->id) : null; diff --git a/src/ValueDefinition.php b/src/ValueDefinition.php index 0ca54f8..2939707 100644 --- a/src/ValueDefinition.php +++ b/src/ValueDefinition.php @@ -4,7 +4,6 @@ namespace Yiisoft\Definitions; -use Override; use Psr\Container\ContainerInterface; use Yiisoft\Definitions\Contract\DefinitionInterface; @@ -33,7 +32,6 @@ public function getType(): ?string return $this->type; } - #[Override] public function resolve(ContainerInterface $container): mixed { return $this->value; From 526b43c1a956b0b47b564c81df210574b5a89fe8 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 10:08:21 +0300 Subject: [PATCH 07/20] mark nullable parameters --- CHANGELOG.md | 1 + .../NotInstantiableClassException.php | 2 +- tests/Support/OptionalConcreteDependency.php | 12 ------------ tests/Support/OptionalInterfaceDependency.php | 12 ------------ .../Unit/Helpers/DefinitionExtractorTest.php | 19 ------------------- tests/Unit/ParameterDefinitionTest.php | 6 +----- 6 files changed, 3 insertions(+), 49 deletions(-) delete mode 100644 tests/Support/OptionalConcreteDependency.php delete mode 100644 tests/Support/OptionalInterfaceDependency.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f35ec04..eb2e2a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Chg #106: Bump minimal required PHP version to 8.1 (@vjik) - Enh #106: Minor performance optimization: use FQN for PHP functions, remove unnecessary conditions (@vjik) - Enh #106: Mark readonly properties (@vjik) +- Bug #105: Explicitly mark nullable parameters (@vjik) ## 3.3.1 December 16, 2024 diff --git a/src/Exception/NotInstantiableClassException.php b/src/Exception/NotInstantiableClassException.php index 16250af..eb1b1dc 100644 --- a/src/Exception/NotInstantiableClassException.php +++ b/src/Exception/NotInstantiableClassException.php @@ -11,7 +11,7 @@ */ final class NotInstantiableClassException extends NotInstantiableException { - public function __construct(string $class, string $message = null, int $code = 0, Exception $previous = null) + public function __construct(string $class, ?string $message = null, int $code = 0, ?Exception $previous = null) { if ($message === null) { $message = "Can not instantiate $class."; diff --git a/tests/Support/OptionalConcreteDependency.php b/tests/Support/OptionalConcreteDependency.php deleted file mode 100644 index e231299..0000000 --- a/tests/Support/OptionalConcreteDependency.php +++ /dev/null @@ -1,12 +0,0 @@ -assertEquals(5, $dependencies['maxGear']->resolve($container)); } - public function testOptionalInterfaceDependency(): void - { - $container = new SimpleContainer(); - /** @var DefinitionInterface[] $dependencies */ - $dependencies = DefinitionExtractor::fromClassName(OptionalInterfaceDependency::class); - $this->assertCount(1, $dependencies); - $this->assertEquals(null, $dependencies['engine']->resolve($container)); - } - public function testNullableInterfaceDependency(): void { $container = new SimpleContainer(); @@ -121,15 +112,6 @@ public function testNullableInterfaceDependency(): void $dependencies['engine']->resolve($container); } - public function testOptionalConcreteDependency(): void - { - $container = new SimpleContainer(); - /** @var DefinitionInterface[] $dependencies */ - $dependencies = DefinitionExtractor::fromClassName(OptionalConcreteDependency::class); - $this->assertCount(1, $dependencies); - $this->assertEquals(null, $dependencies['car']->resolve($container)); - } - public function testNullableConcreteDependency(): void { $container = new SimpleContainer(); @@ -152,7 +134,6 @@ public function testNullableOptionalConcreteDependency(): void public function testNullableOptionalInterfaceDependency(): void { $container = new SimpleContainer(); - /** @var DefinitionInterface[] $dependencies */ $dependencies = DefinitionExtractor::fromClassName(NullableOptionalInterfaceDependency::class); $this->assertCount(1, $dependencies); $this->assertEquals(null, $dependencies['engine']->resolve($container)); diff --git a/tests/Unit/ParameterDefinitionTest.php b/tests/Unit/ParameterDefinitionTest.php index 7084fe7..3070a79 100644 --- a/tests/Unit/ParameterDefinitionTest.php +++ b/tests/Unit/ParameterDefinitionTest.php @@ -84,7 +84,7 @@ public static function dataHasValue(): array static fn ( string $a, ?string $b, - string $c = null, + ?string $c = null, string $d = 'hello' ): bool => true ); @@ -138,10 +138,6 @@ public static function dataResolve(): array 7, self::getFirstParameter(static fn (int $n = 7) => true), ], - 'defaultNull' => [ - null, - self::getFirstParameter(static fn (int $n = null) => true), - ], 'nullableAndDefaultNull' => [ null, self::getFirstParameter(static fn (?int $n = null) => true), From 4638a63303f92e5b50e89e23bfb02bcd6ccd6c94 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 10:31:01 +0300 Subject: [PATCH 08/20] Improve definition validation for readonly properties --- CHANGELOG.md | 1 + src/Helpers/DefinitionValidator.php | 5 +++-- tests/Support/ReadonlyProperty.php | 10 ++++++++++ .../Unit/Helpers/DefinitionValidatorTest.php | 19 +++++++++++++++++-- 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/Support/ReadonlyProperty.php diff --git a/CHANGELOG.md b/CHANGELOG.md index eb2e2a8..7f974b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Enh #106: Minor performance optimization: use FQN for PHP functions, remove unnecessary conditions (@vjik) - Enh #106: Mark readonly properties (@vjik) - Bug #105: Explicitly mark nullable parameters (@vjik) +- Enh #106: Improve definition validation for readonly properties (@vjik) ## 3.3.1 December 16, 2024 diff --git a/src/Helpers/DefinitionValidator.php b/src/Helpers/DefinitionValidator.php index 0abd7b5..3913cf4 100644 --- a/src/Helpers/DefinitionValidator.php +++ b/src/Helpers/DefinitionValidator.php @@ -11,6 +11,7 @@ use Yiisoft\Definitions\Contract\ReferenceInterface; use Yiisoft\Definitions\Exception\InvalidConfigException; +use function count; use function in_array; use function is_array; use function is_callable; @@ -85,7 +86,7 @@ public static function validateArrayDefinition(array $definition, ?string $id = } $classPublicProperties = []; foreach ($classReflection->getProperties() as $reflectionProperty) { - if ($reflectionProperty->isPublic()) { + if ($reflectionProperty->isPublic() && !$reflectionProperty->isReadOnly()) { $classPublicProperties[] = $reflectionProperty->getName(); } } @@ -261,7 +262,7 @@ private static function validateProperty( } elseif (!in_array($parsedKey, $classPublicProperties, true)) { throw new InvalidConfigException( sprintf( - 'Invalid definition: property "%s" must be public.', + 'Invalid definition: property "%s" must be public and writable.', $className . '::' . $key, ) ); diff --git a/tests/Support/ReadonlyProperty.php b/tests/Support/ReadonlyProperty.php new file mode 100644 index 0000000..b547447 --- /dev/null +++ b/tests/Support/ReadonlyProperty.php @@ -0,0 +1,10 @@ +expectExceptionMessage($message); DefinitionValidator::validate($config); } + + public function testReadonlyProperty(): void + { + $definition = [ + 'class' => ReadonlyProperty::class, + '$var' => 'test', + ]; + + $this->expectException(InvalidConfigException::class); + $this->expectExceptionMessage( + 'Invalid definition: property "Yiisoft\Definitions\Tests\Support\ReadonlyProperty::$var" must be public and writable.' + ); + DefinitionValidator::validate($definition); + } } From 70b9313bc3cd96f08f8006f49d87bcc6fd98a537 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 10:51:11 +0300 Subject: [PATCH 09/20] asymmetric visibility --- CHANGELOG.md | 2 +- phpunit.xml.dist | 1 + src/Helpers/DefinitionValidator.php | 27 ++++++++++++- .../DefinitionValidatorTest.php | 40 +++++++++++++++++++ .../Php8_4/AsymmetricVisibility/PublicGet.php | 11 +++++ 5 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 tests/Php8_4/AsymmetricVisibility/DefinitionValidatorTest.php create mode 100644 tests/Php8_4/AsymmetricVisibility/PublicGet.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f974b1..f7cb787 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - Enh #106: Minor performance optimization: use FQN for PHP functions, remove unnecessary conditions (@vjik) - Enh #106: Mark readonly properties (@vjik) - Bug #105: Explicitly mark nullable parameters (@vjik) -- Enh #106: Improve definition validation for readonly properties (@vjik) +- Enh #106: Improve definition validation for readonly properties and properties with asymmetric visibility (@vjik) ## 3.3.1 December 16, 2024 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index c21dbf0..00bbbd3 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -21,6 +21,7 @@ ./tests/Unit ./tests/Php8_2 + ./tests/Php8_4 diff --git a/src/Helpers/DefinitionValidator.php b/src/Helpers/DefinitionValidator.php index 3913cf4..b6d01f8 100644 --- a/src/Helpers/DefinitionValidator.php +++ b/src/Helpers/DefinitionValidator.php @@ -6,6 +6,7 @@ use ReflectionClass; use ReflectionException; +use ReflectionProperty; use Yiisoft\Definitions\ArrayDefinition; use Yiisoft\Definitions\Contract\DefinitionInterface; use Yiisoft\Definitions\Contract\ReferenceInterface; @@ -86,7 +87,7 @@ public static function validateArrayDefinition(array $definition, ?string $id = } $classPublicProperties = []; foreach ($classReflection->getProperties() as $reflectionProperty) { - if ($reflectionProperty->isPublic() && !$reflectionProperty->isReadOnly()) { + if (self::isPublicWritableProperty($reflectionProperty)) { $classPublicProperties[] = $reflectionProperty->getName(); } } @@ -328,4 +329,28 @@ private static function validateString(mixed $class): void throw new InvalidConfigException('Invalid definition: class name must be a non-empty string.'); } } + + private static function isPublicWritableProperty(ReflectionProperty $property): bool + { + if (!$property->isPublic()) { + return false; + } + + if ($property->isReadOnly()) { + return false; + } + + if (PHP_VERSION_ID < 80400) { + return true; + } + + $modifiers = $property->getModifiers(); + if ($modifiers & ReflectionProperty::IS_PRIVATE_SET + || $modifiers & ReflectionProperty::IS_PROTECTED_SET + ) { + return false; + } + + return true; + } } diff --git a/tests/Php8_4/AsymmetricVisibility/DefinitionValidatorTest.php b/tests/Php8_4/AsymmetricVisibility/DefinitionValidatorTest.php new file mode 100644 index 0000000..a08a845 --- /dev/null +++ b/tests/Php8_4/AsymmetricVisibility/DefinitionValidatorTest.php @@ -0,0 +1,40 @@ + PublicGet::class, + '$privateVar' => 'test', + ]; + + $this->expectException(InvalidConfigException::class); + $this->expectExceptionMessage( + 'Invalid definition: property "Yiisoft\Definitions\Tests\Php8_4\AsymmetricVisibility\PublicGet::$privateVar" must be public and writable.' + ); + DefinitionValidator::validate($definition); + } + + public function testProtectedSet(): void + { + $definition = [ + 'class' => PublicGet::class, + '$protectedVar' => 'test', + ]; + + $this->expectException(InvalidConfigException::class); + $this->expectExceptionMessage( + 'Invalid definition: property "Yiisoft\Definitions\Tests\Php8_4\AsymmetricVisibility\PublicGet::$protectedVar" must be public and writable.' + ); + DefinitionValidator::validate($definition); + } +} diff --git a/tests/Php8_4/AsymmetricVisibility/PublicGet.php b/tests/Php8_4/AsymmetricVisibility/PublicGet.php new file mode 100644 index 0000000..ffbfaef --- /dev/null +++ b/tests/Php8_4/AsymmetricVisibility/PublicGet.php @@ -0,0 +1,11 @@ + Date: Tue, 18 Feb 2025 07:51:35 +0000 Subject: [PATCH 10/20] Apply fixes from StyleCI --- src/Helpers/DefinitionValidator.php | 10 +++++----- tests/Unit/Helpers/DefinitionExtractorTest.php | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Helpers/DefinitionValidator.php b/src/Helpers/DefinitionValidator.php index b6d01f8..1728a81 100644 --- a/src/Helpers/DefinitionValidator.php +++ b/src/Helpers/DefinitionValidator.php @@ -345,12 +345,12 @@ private static function isPublicWritableProperty(ReflectionProperty $property): } $modifiers = $property->getModifiers(); - if ($modifiers & ReflectionProperty::IS_PRIVATE_SET + return !($modifiers & ReflectionProperty::IS_PRIVATE_SET || $modifiers & ReflectionProperty::IS_PROTECTED_SET - ) { - return false; - } + ) + + - return true; + ; } } diff --git a/tests/Unit/Helpers/DefinitionExtractorTest.php b/tests/Unit/Helpers/DefinitionExtractorTest.php index 5a1885d..9fb941e 100644 --- a/tests/Unit/Helpers/DefinitionExtractorTest.php +++ b/tests/Unit/Helpers/DefinitionExtractorTest.php @@ -20,8 +20,6 @@ use Yiisoft\Definitions\Tests\Support\GearBox; use Yiisoft\Definitions\Tests\Support\NullableConcreteDependency; use Yiisoft\Definitions\Tests\Support\NullableInterfaceDependency; -use Yiisoft\Definitions\Tests\Support\OptionalConcreteDependency; -use Yiisoft\Definitions\Tests\Support\OptionalInterfaceDependency; use Yiisoft\Definitions\Tests\Support\NullableOptionalConcreteDependency; use Yiisoft\Definitions\Tests\Support\NullableOptionalInterfaceDependency; use Yiisoft\Definitions\Tests\Support\RedChair; From 079436888d6a6e901ca8bf8fbb2008cdebccacef Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 10:55:29 +0300 Subject: [PATCH 11/20] fix styleci --- .styleci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.styleci.yml b/.styleci.yml index e121039..635a6b8 100644 --- a/.styleci.yml +++ b/.styleci.yml @@ -1,7 +1,7 @@ preset: psr12 risky: true -version: 8.2 +version: 8.4 finder: exclude: From cd2b1de2226e0f2e45ebba101e4e4b702b4a9f1a Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 10:58:40 +0300 Subject: [PATCH 12/20] fix --- composer.json | 2 +- src/Helpers/DefinitionValidator.php | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index e7cc206..cd3296a 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,7 @@ "roave/infection-static-analysis-plugin": "^1.35", "spatie/phpunit-watcher": "^1.24", "vimeo/psalm": "^5.26.1 || ^6.7.1", - "yiisoft/test-support": "^3.0" + "yiisoft/test-support": "^3.0.1" }, "autoload": { "psr-4": { diff --git a/src/Helpers/DefinitionValidator.php b/src/Helpers/DefinitionValidator.php index 1728a81..744317f 100644 --- a/src/Helpers/DefinitionValidator.php +++ b/src/Helpers/DefinitionValidator.php @@ -345,12 +345,12 @@ private static function isPublicWritableProperty(ReflectionProperty $property): } $modifiers = $property->getModifiers(); + + /** + * @pslam-suppress UndefinedConstant, MixedOperand Needs for PHP 8.3 or lower + */ return !($modifiers & ReflectionProperty::IS_PRIVATE_SET || $modifiers & ReflectionProperty::IS_PROTECTED_SET - ) - - - - ; + ); } } From fe8181ca65d295b221afe2e35c73223982fd65fd Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 11:00:47 +0300 Subject: [PATCH 13/20] fix --- src/Helpers/DefinitionValidator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Helpers/DefinitionValidator.php b/src/Helpers/DefinitionValidator.php index 744317f..3025217 100644 --- a/src/Helpers/DefinitionValidator.php +++ b/src/Helpers/DefinitionValidator.php @@ -347,7 +347,7 @@ private static function isPublicWritableProperty(ReflectionProperty $property): $modifiers = $property->getModifiers(); /** - * @pslam-suppress UndefinedConstant, MixedOperand Needs for PHP 8.3 or lower + * @psalm-suppress UndefinedConstant, MixedOperand Needs for PHP 8.3 or lower */ return !($modifiers & ReflectionProperty::IS_PRIVATE_SET || $modifiers & ReflectionProperty::IS_PROTECTED_SET From cd769f4284a6d96ab84f4d698f3f510d1cc66167 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 13:09:35 +0300 Subject: [PATCH 14/20] fix --- .php-cs-fixer.dist.php | 10 ++++++---- composer.json | 2 +- src/Helpers/DefinitionValidator.php | 3 ++- tests/Php8_2/ParameterDefinitionTest.php | 2 +- .../AsymmetricVisibility/DefinitionValidatorTest.php | 4 ++-- .../UnionTypeWithIntersectionTypeDependency.php | 5 ++--- tests/Unit/Helpers/DefinitionValidatorTest.php | 2 +- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 43dd8b5..5c4e99a 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -6,10 +6,12 @@ use PhpCsFixer\Finder; use PhpCsFixer\Runner\Parallel\ParallelConfigFactory; -$finder = (new Finder())->in([ - __DIR__ . '/src', - __DIR__ . '/tests', -]); +$finder = (new Finder()) + ->in([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) + ->exclude('Php8_4/'); return (new Config()) ->setParallelConfig(ParallelConfigFactory::detect()) diff --git a/composer.json b/composer.json index 4e281f4..276b7ad 100644 --- a/composer.json +++ b/composer.json @@ -58,7 +58,7 @@ } }, "scripts": { - "php-cs-fixer": "php-cs-fixer fix", + "php-cs-fixer": "PHP_CS_FIXER_IGNORE_ENV=1 php-cs-fixer fix", "rector": "rector", "test": "phpunit --testdox --no-interaction", "test-watch": "phpunit-watcher watch" diff --git a/src/Helpers/DefinitionValidator.php b/src/Helpers/DefinitionValidator.php index 924dd3c..19c405a 100644 --- a/src/Helpers/DefinitionValidator.php +++ b/src/Helpers/DefinitionValidator.php @@ -349,7 +349,8 @@ private static function isPublicWritableProperty(ReflectionProperty $property): /** * @psalm-suppress UndefinedConstant, MixedOperand Needs for PHP 8.3 or lower */ - return !($modifiers & ReflectionProperty::IS_PRIVATE_SET + return !( + $modifiers & ReflectionProperty::IS_PRIVATE_SET || $modifiers & ReflectionProperty::IS_PROTECTED_SET ); } diff --git a/tests/Php8_2/ParameterDefinitionTest.php b/tests/Php8_2/ParameterDefinitionTest.php index 75caf79..9d57783 100644 --- a/tests/Php8_2/ParameterDefinitionTest.php +++ b/tests/Php8_2/ParameterDefinitionTest.php @@ -22,7 +22,7 @@ public function testResolveUnionTypeWithIntersectionType(): void ]); $definition = new ParameterDefinition( - $this->getFirstParameter(fn (Bike|(GearBox&stdClass)|Chair $class) => true) + $this->getFirstParameter(fn(Bike|(GearBox&stdClass)|Chair $class) => true), ); $result = $definition->resolve($container); diff --git a/tests/Php8_4/AsymmetricVisibility/DefinitionValidatorTest.php b/tests/Php8_4/AsymmetricVisibility/DefinitionValidatorTest.php index a08a845..dfed394 100644 --- a/tests/Php8_4/AsymmetricVisibility/DefinitionValidatorTest.php +++ b/tests/Php8_4/AsymmetricVisibility/DefinitionValidatorTest.php @@ -19,7 +19,7 @@ public function testPrivateSet(): void $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage( - 'Invalid definition: property "Yiisoft\Definitions\Tests\Php8_4\AsymmetricVisibility\PublicGet::$privateVar" must be public and writable.' + 'Invalid definition: property "Yiisoft\Definitions\Tests\Php8_4\AsymmetricVisibility\PublicGet::$privateVar" must be public and writable.', ); DefinitionValidator::validate($definition); } @@ -33,7 +33,7 @@ public function testProtectedSet(): void $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage( - 'Invalid definition: property "Yiisoft\Definitions\Tests\Php8_4\AsymmetricVisibility\PublicGet::$protectedVar" must be public and writable.' + 'Invalid definition: property "Yiisoft\Definitions\Tests\Php8_4\AsymmetricVisibility\PublicGet::$protectedVar" must be public and writable.', ); DefinitionValidator::validate($definition); } diff --git a/tests/Support/UnionTypeWithIntersectionTypeDependency.php b/tests/Support/UnionTypeWithIntersectionTypeDependency.php index 46cb22e..b248dcb 100644 --- a/tests/Support/UnionTypeWithIntersectionTypeDependency.php +++ b/tests/Support/UnionTypeWithIntersectionTypeDependency.php @@ -7,7 +7,6 @@ final class UnionTypeWithIntersectionTypeDependency { public function __construct( - public Bike|(GearBox&stdClass)|Chair $dependency - ) { - } + public Bike|(GearBox&stdClass)|Chair $dependency, + ) {} } diff --git a/tests/Unit/Helpers/DefinitionValidatorTest.php b/tests/Unit/Helpers/DefinitionValidatorTest.php index a6f0deb..108e709 100644 --- a/tests/Unit/Helpers/DefinitionValidatorTest.php +++ b/tests/Unit/Helpers/DefinitionValidatorTest.php @@ -378,7 +378,7 @@ public function testReadonlyProperty(): void $this->expectException(InvalidConfigException::class); $this->expectExceptionMessage( - 'Invalid definition: property "Yiisoft\Definitions\Tests\Support\ReadonlyProperty::$var" must be public and writable.' + 'Invalid definition: property "Yiisoft\Definitions\Tests\Support\ReadonlyProperty::$var" must be public and writable.', ); DefinitionValidator::validate($definition); } From 433c8c6316b285b09eca0729b70182801af3a3f9 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 13:14:33 +0300 Subject: [PATCH 15/20] ignore mutant --- infection.json.dist | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/infection.json.dist b/infection.json.dist index 3776e22..2185614 100644 --- a/infection.json.dist +++ b/infection.json.dist @@ -11,6 +11,11 @@ } }, "mutators": { - "@default": true + "@default": true, + "LessThan": { + "ignoreSourceCodeByRegex": [ + ".*\\(PHP_VERSION_ID .*" + ] + } } } From 7503fb54a3d0313e4e8f9d43c2b10cbe4bbd73b8 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 13:23:22 +0300 Subject: [PATCH 16/20] kill mutant --- .github/workflows/mutation.yml | 2 +- src/ParameterDefinition.php | 5 +-- tests/Unit/ParameterDefinitionTest.php | 54 +++++++++++++++++++------- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/.github/workflows/mutation.yml b/.github/workflows/mutation.yml index dc464eb..7a54fcc 100644 --- a/.github/workflows/mutation.yml +++ b/.github/workflows/mutation.yml @@ -29,6 +29,6 @@ jobs: os: >- ['ubuntu-latest'] php: >- - ['8.3'] + ['8.4'] secrets: STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }} diff --git a/src/ParameterDefinition.php b/src/ParameterDefinition.php index 0fbe51c..34fff5a 100644 --- a/src/ParameterDefinition.php +++ b/src/ParameterDefinition.php @@ -216,10 +216,7 @@ private function getCallable(): string if ($class !== null) { $callable[] = $class->getName(); } - $callable[] = $this->parameter - ->getDeclaringFunction() - ->getName() . - '()'; + $callable[] = $this->parameter->getDeclaringFunction()->getName() . '()'; return implode('::', $callable); } diff --git a/tests/Unit/ParameterDefinitionTest.php b/tests/Unit/ParameterDefinitionTest.php index 4a12727..41c856f 100644 --- a/tests/Unit/ParameterDefinitionTest.php +++ b/tests/Unit/ParameterDefinitionTest.php @@ -13,6 +13,7 @@ use ReflectionParameter; use RuntimeException; use stdClass; +use Throwable; use Yiisoft\Definitions\Exception\InvalidConfigException; use Yiisoft\Definitions\Exception\NotInstantiableException; use Yiisoft\Definitions\ParameterDefinition; @@ -163,13 +164,20 @@ public function testResolveNonTypedParameter(): void ); $container = new SimpleContainer(); - $this->expectException(NotInstantiableException::class); - $this->expectExceptionMessage( - 'Can not determine value of the "x" parameter without type when instantiating ' - . '"Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::', + $exception = null; + try { + $definition->resolve($container); + } catch (Throwable $exception) {} + + $this->assertInstanceOf(NotInstantiableException::class, $exception); + $this->assertStringStartsWith( + 'Can not determine value of the "x" parameter without type when instantiating "Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::', + $exception->getMessage(), + ); + $this->assertStringEndsWith( + 'Please specify argument explicitly.', + $exception->getMessage(), ); - $this->expectExceptionMessage('Please specify argument explicitly.'); - $definition->resolve($container); } public function testResolveBuiltinParameter(): void @@ -181,13 +189,20 @@ public function testResolveBuiltinParameter(): void ); $container = new SimpleContainer(); - $this->expectException(NotInstantiableException::class); - $this->expectExceptionMessage( - 'Can not determine value of the "n" parameter of type "int" when instantiating ' - . '"Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::', + $exception = null; + try { + $definition->resolve($container); + } catch (Throwable $exception) {} + + $this->assertInstanceOf(NotInstantiableException::class, $exception); + $this->assertStringStartsWith( + 'Can not determine value of the "n" parameter of type "int" when instantiating "Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::', + $exception->getMessage(), + ); + $this->assertStringEndsWith( + 'Please specify argument explicitly.', + $exception->getMessage(), ); - $this->expectExceptionMessage('Please specify argument explicitly.'); - $definition->resolve($container); } public function testResolveSelf(): void @@ -416,9 +431,18 @@ public function testNotResolveIntersectionType(): void self::getFirstParameter(fn(GearBox&stdClass $class) => true), ); - $this->expectException(NotInstantiableException::class); - $this->expectExceptionMessage('Can not determine value of the "class" parameter of type '); - $definition->resolve($container); + $exception = null; + try { + $definition->resolve($container); + } catch (Throwable $exception) { + } + + $this->assertInstanceOf(NotInstantiableException::class, $exception); + $this->assertStringStartsWith( + 'Can not determine value of the "class" parameter of type "Yiisoft\Definitions\Tests\Support\GearBox&stdClass" when instantiating "Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::{closure', + $exception->getMessage(), + ); + $this->assertStringEndsWith('()". Please specify argument explicitly.', $exception->getMessage()); } /** From 9ec09fa4476b167cc2ce26ec8e6b6a7c512a6f0a Mon Sep 17 00:00:00 2001 From: vjik <525501+vjik@users.noreply.github.com> Date: Tue, 18 Feb 2025 10:33:05 +0000 Subject: [PATCH 17/20] Apply PHP CS Fixer and Rector changes (CI) --- tests/Unit/ParameterDefinitionTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/Unit/ParameterDefinitionTest.php b/tests/Unit/ParameterDefinitionTest.php index 41c856f..a6b3c07 100644 --- a/tests/Unit/ParameterDefinitionTest.php +++ b/tests/Unit/ParameterDefinitionTest.php @@ -167,7 +167,8 @@ public function testResolveNonTypedParameter(): void $exception = null; try { $definition->resolve($container); - } catch (Throwable $exception) {} + } catch (Throwable $exception) { + } $this->assertInstanceOf(NotInstantiableException::class, $exception); $this->assertStringStartsWith( @@ -192,7 +193,8 @@ public function testResolveBuiltinParameter(): void $exception = null; try { $definition->resolve($container); - } catch (Throwable $exception) {} + } catch (Throwable $exception) { + } $this->assertInstanceOf(NotInstantiableException::class, $exception); $this->assertStringStartsWith( From 99cabbd20b922f0eab5c5ea20add6f4daf5e417d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 13:35:31 +0300 Subject: [PATCH 18/20] fix --- tests/Unit/ParameterDefinitionTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/ParameterDefinitionTest.php b/tests/Unit/ParameterDefinitionTest.php index a6b3c07..8357994 100644 --- a/tests/Unit/ParameterDefinitionTest.php +++ b/tests/Unit/ParameterDefinitionTest.php @@ -441,10 +441,10 @@ public function testNotResolveIntersectionType(): void $this->assertInstanceOf(NotInstantiableException::class, $exception); $this->assertStringStartsWith( - 'Can not determine value of the "class" parameter of type "Yiisoft\Definitions\Tests\Support\GearBox&stdClass" when instantiating "Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::{closure', + 'Can not determine value of the "class" parameter of type "Yiisoft\Definitions\Tests\Support\GearBox&stdClass" when instantiating "Yiisoft\Definitions\Tests\Unit\ParameterDefinitionTest::', $exception->getMessage(), ); - $this->assertStringEndsWith('()". Please specify argument explicitly.', $exception->getMessage()); + $this->assertStringEndsWith('}()". Please specify argument explicitly.', $exception->getMessage()); } /** From daa0f2776d0c0fbee904da9264f87a1d413dde1f Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 18 Feb 2025 13:41:40 +0300 Subject: [PATCH 19/20] fix changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7cb787..a71038c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - Enh #106: Minor performance optimization: use FQN for PHP functions, remove unnecessary conditions (@vjik) - Enh #106: Mark readonly properties (@vjik) - Bug #105: Explicitly mark nullable parameters (@vjik) -- Enh #106: Improve definition validation for readonly properties and properties with asymmetric visibility (@vjik) +- Enh #105: Improve definition validation for readonly properties and properties with asymmetric visibility (@vjik) ## 3.3.1 December 16, 2024 From 11f6045f61bb3ea4db15262415b2b4f04030ddeb Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Thu, 20 Feb 2025 14:15:49 +0300 Subject: [PATCH 20/20] Update src/Helpers/DefinitionValidator.php Co-authored-by: Sergei Tigrov --- src/Helpers/DefinitionValidator.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Helpers/DefinitionValidator.php b/src/Helpers/DefinitionValidator.php index 19c405a..110732e 100644 --- a/src/Helpers/DefinitionValidator.php +++ b/src/Helpers/DefinitionValidator.php @@ -349,9 +349,6 @@ private static function isPublicWritableProperty(ReflectionProperty $property): /** * @psalm-suppress UndefinedConstant, MixedOperand Needs for PHP 8.3 or lower */ - return !( - $modifiers & ReflectionProperty::IS_PRIVATE_SET - || $modifiers & ReflectionProperty::IS_PROTECTED_SET - ); + return ($modifiers & (ReflectionProperty::IS_PRIVATE_SET | ReflectionProperty::IS_PROTECTED_SET)) === 0; } }