From 984b5a6a397807e5e56c1e9079bba5cb146e92af Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 19:19:46 +0100 Subject: [PATCH 01/53] Drop PHP 7 support to improve type inference Because we operate with reflection symbols for attributes, we want to be on at least PHP 8.0, in order to have Psalm and PHPUnit access all the relevant types related to attributes. Signed-off-by: Marco Pivetta --- composer.json | 4 ++-- composer.lock | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 5bc1efeb..d815a0bc 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "homepage": "https://laminas.dev", "license": "BSD-3-Clause", "require": { - "php": ">=7.4, <8.2" + "php": "~8.0.0 || ~8.1.0" }, "require-dev": { "ext-phar": "*", @@ -29,7 +29,7 @@ "dealerdirect/phpcodesniffer-composer-installer": true }, "platform": { - "php": "7.4.99" + "php": "8.0.99" }, "sort-packages": true }, diff --git a/composer.lock b/composer.lock index 697dfc2f..894c9a35 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bdac2a2a26a0a63994c2cbae675d445b", + "content-hash": "c8cba8b0ed1c6fbb420abd52a929731a", "packages": [], "packages-dev": [ { @@ -4415,13 +4415,13 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.4, <8.2" + "php": "~8.0.0 || ~8.1.0" }, "platform-dev": { "ext-phar": "*" }, "platform-overrides": { - "php": "7.4.99" + "php": "8.0.99" }, "plugin-api-version": "2.3.0" } From b310381955a67ec09c2a11ef9691216ed346f6e9 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 19:23:20 +0100 Subject: [PATCH 02/53] Deprecating `ParameterReflection#detectType()` and its callers This API is old, bad, and not really useful, as it produces a string representation of functions/methods that doesn't bring much to the table: in fact, it is easier to inspect the AST of a symbol, than to look at its string or array prototype. These methods will be dropped in the next major release, as they are prone to crashes due to union/intersection types on PHP 8.1 and newer, and it is not worth investing the time to fix them. Signed-off-by: Marco Pivetta --- psalm-baseline.xml | 78 ++++++++++++++++---------- src/Reflection/FunctionReflection.php | 4 ++ src/Reflection/MethodReflection.php | 4 ++ src/Reflection/ParameterReflection.php | 10 ++-- 4 files changed, 61 insertions(+), 35 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index bca02bc8..360883e1 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -106,9 +106,6 @@ $namespaceAlias - - method_exists($constReflection, 'isFinal') - is_array($constant) @@ -284,6 +281,9 @@ getName getName + + ReflectionEnumUnitCase + getBackingType getCases @@ -307,9 +307,12 @@ $docBlock - + $uses - + + + array<int, array{string, null|string, false|null|string}> + $value @@ -333,9 +336,6 @@ $use $value - - array<int, array{string, null|string, false|null|string}> - (string) $body (string) $filename @@ -382,10 +382,9 @@ DocBlockGenerator::fromArray($value) ParameterGenerator::fromArray($parameter) - + $array['name'] $parameterOutput - $reflectionMethod->isStatic() $value $value $value @@ -478,9 +477,6 @@ $reflectionProperty->getDocBlock() - - method_exists($reflectionProperty, 'isReadonly') - new static($array['name']) new static() @@ -616,14 +612,18 @@ - + allowsNull getName getName getParentClass - getTypes - + + + + ReflectionIntersectionType + ReflectionIntersectionType + @@ -876,6 +876,9 @@ + + detectType + ParameterReflection[] @@ -919,6 +922,9 @@ + + detectType + bool @@ -963,6 +969,9 @@ $phpReflection->getName() + + isPromoted + #[ReturnTypeWillChange] #[ReturnTypeWillChange] @@ -988,9 +997,10 @@ $type - + getName getName + isBuiltin @@ -1871,6 +1881,10 @@ __NAMESPACE__ . '\\' . $functionName + + getPrototype + getPrototype + 'LaminasTest\Code\Reflection\TestAsset\function1' 'LaminasTest\Code\Reflection\TestAsset\function1' @@ -1984,6 +1998,16 @@ 'ReflectionException' __NAMESPACE__ . '\\' . $className + + getPrototype + getPrototype + getPrototype + getPrototype + getPrototype + getPrototype + getPrototype + getPrototype + testCanParseClassBodyWhenUsingTrait testCodeGetBodyReturnsEmptyWithCommentedFunction @@ -2003,6 +2027,13 @@ + + detectType + detectType + detectType + detectType + detectType + testCallableTypeHint testClassReturn @@ -2552,19 +2583,6 @@ objectParameter - - - bool|null - bool|null $parameter - bool|string|null - false|self - false|self $parameter - mixed - mixed - null|bool - null|bool $parameter - - InternalHintsClass diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index 4c547db1..bf5121f2 100644 --- a/src/Reflection/FunctionReflection.php +++ b/src/Reflection/FunctionReflection.php @@ -128,6 +128,10 @@ public function getContents($includeDocBlock = true) * * @param string $format * @return array|string + * + * @deprecated this method is unreliable, and should not be used: it will be removed in the next major release. + * It may crash on parameters with union types, and will return relative types, instead of + * FQN references */ public function getPrototype($format = self::PROTOTYPE_AS_ARRAY) { diff --git a/src/Reflection/MethodReflection.php b/src/Reflection/MethodReflection.php index b026b703..1b0be0e9 100644 --- a/src/Reflection/MethodReflection.php +++ b/src/Reflection/MethodReflection.php @@ -87,6 +87,10 @@ public function getDeclaringClass() * * @param string $format * @return array|string + * + * @deprecated this method is unreliable, and should not be used: it will be removed in the next major release. + * It may crash on parameters with union types, and will return relative types, instead of + * FQN references */ #[ReturnTypeWillChange] public function getPrototype($format = self::PROTOTYPE_AS_ARRAY) diff --git a/src/Reflection/ParameterReflection.php b/src/Reflection/ParameterReflection.php index 5e11ec3a..f68bbdc9 100644 --- a/src/Reflection/ParameterReflection.php +++ b/src/Reflection/ParameterReflection.php @@ -73,6 +73,10 @@ public function getDeclaringFunction() * Get parameter type * * @return string|null + * + * @deprecated this method is unreliable, and should not be used: it will be removed in the next major release. + * It may crash on parameters with union types, and will return relative types, instead of + * FQN references */ public function detectType() { @@ -135,11 +139,7 @@ public function __toString() /** @psalm-pure */ public function isPromoted(): bool { - if (! method_exists(parent::class, 'isPromoted')) { - return false; - } - - return (bool) parent::isPromoted(); + return parent::isPromoted(); } public function isPublicPromoted(): bool From 9f5036b01500cd83b4ee7ee54c890c0135e2d654 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 20:17:59 +0100 Subject: [PATCH 03/53] Further restricting supported PHP version to `~8.1.0` This is because we really do a lot of stuff with ENUMs, and it is a massive pain to run all checks on an older inferred PHP version. By doing this, we can refine the types of various ENUM structures in our core logic in subsequent commits. Signed-off-by: Marco Pivetta --- composer.json | 4 +- composer.lock | 291 +++++++++++++++++++------------------------------- 2 files changed, 109 insertions(+), 186 deletions(-) diff --git a/composer.json b/composer.json index d815a0bc..5ad717b4 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,7 @@ "homepage": "https://laminas.dev", "license": "BSD-3-Clause", "require": { - "php": "~8.0.0 || ~8.1.0" + "php": "~8.1.0" }, "require-dev": { "ext-phar": "*", @@ -29,7 +29,7 @@ "dealerdirect/phpcodesniffer-composer-installer": true }, "platform": { - "php": "8.0.99" + "php": "8.1.99" }, "sort-packages": true }, diff --git a/composer.lock b/composer.lock index 894c9a35..c4ee1210 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c8cba8b0ed1c6fbb420abd52a929731a", + "content-hash": "97fe4a5c04c62c12e53d5451cbd94c2f", "packages": [], "packages-dev": [ { @@ -248,16 +248,16 @@ }, { "name": "composer/pcre", - "version": "3.0.2", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb" + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb", - "reference": "4482b6409ca6bfc2af043a5711cd21ac3e7a8dfb", + "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", "shasum": "" }, "require": { @@ -299,7 +299,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.0.2" + "source": "https://github.com/composer/pcre/tree/3.1.0" }, "funding": [ { @@ -315,7 +315,7 @@ "type": "tidelift" } ], - "time": "2022-11-03T20:24:16+00:00" + "time": "2022-11-17T09:50:14+00:00" }, { "name": "composer/semver", @@ -954,31 +954,30 @@ }, { "name": "laminas/laminas-stdlib", - "version": "3.13.0", + "version": "3.15.0", "source": { "type": "git", "url": "https://github.com/laminas/laminas-stdlib.git", - "reference": "66a6d03c381f6c9f1dd988bf8244f9afb9380d76" + "reference": "63b66bd4b696f024f42616b9d95cdb10e5109c27" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/66a6d03c381f6c9f1dd988bf8244f9afb9380d76", - "reference": "66a6d03c381f6c9f1dd988bf8244f9afb9380d76", + "url": "https://api.github.com/repos/laminas/laminas-stdlib/zipball/63b66bd4b696f024f42616b9d95cdb10e5109c27", + "reference": "63b66bd4b696f024f42616b9d95cdb10e5109c27", "shasum": "" }, "require": { - "php": "^7.4 || ~8.0.0 || ~8.1.0" + "php": "~8.0.0 || ~8.1.0 || ~8.2.0" }, "conflict": { "zendframework/zend-stdlib": "*" }, "require-dev": { - "laminas/laminas-coding-standard": "~2.3.0", + "laminas/laminas-coding-standard": "^2.4.0", "phpbench/phpbench": "^1.2.6", - "phpstan/phpdoc-parser": "^0.5.4", - "phpunit/phpunit": "^9.5.23", + "phpunit/phpunit": "^9.5.25", "psalm/plugin-phpunit": "^0.17.0", - "vimeo/psalm": "^4.26" + "vimeo/psalm": "^4.28" }, "type": "library", "autoload": { @@ -1010,7 +1009,7 @@ "type": "community_bridge" } ], - "time": "2022-08-24T13:56:50+00:00" + "time": "2022-10-10T19:10:24+00:00" }, { "name": "myclabs/deep-copy", @@ -1553,16 +1552,16 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.18", + "version": "9.2.19", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a" + "reference": "c77b56b63e3d2031bd8997fcec43c1925ae46559" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/12fddc491826940cf9b7e88ad9664cf51f0f6d0a", - "reference": "12fddc491826940cf9b7e88ad9664cf51f0f6d0a", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c77b56b63e3d2031bd8997fcec43c1925ae46559", + "reference": "c77b56b63e3d2031bd8997fcec43c1925ae46559", "shasum": "" }, "require": { @@ -1618,7 +1617,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.18" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.19" }, "funding": [ { @@ -1626,7 +1625,7 @@ "type": "github" } ], - "time": "2022-10-27T13:35:33+00:00" + "time": "2022-11-18T07:47:47+00:00" }, { "name": "phpunit/php-file-iterator", @@ -2033,20 +2032,20 @@ }, { "name": "psr/cache", - "version": "1.0.1", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/cache.git", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { @@ -2066,7 +2065,7 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], "description": "Common interface for caching libraries", @@ -2076,28 +2075,33 @@ "psr-6" ], "support": { - "source": "https://github.com/php-fig/cache/tree/master" + "source": "https://github.com/php-fig/cache/tree/3.0.0" }, - "time": "2016-08-06T20:24:11+00:00" + "time": "2021-02-03T23:26:27+00:00" }, { "name": "psr/container", - "version": "1.1.2", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", - "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { "php": ">=7.4.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { "Psr\\Container\\": "src/" @@ -2124,36 +2128,36 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.2" + "source": "https://github.com/php-fig/container/tree/2.0.2" }, - "time": "2021-11-05T16:50:12+00:00" + "time": "2021-11-05T16:47:00+00:00" }, { "name": "psr/log", - "version": "1.1.4", + "version": "3.0.0", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", + "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=8.0.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "3.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Log\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2174,9 +2178,9 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" + "source": "https://github.com/php-fig/log/tree/3.0.0" }, - "time": "2021-05-03T11:20:27+00:00" + "time": "2021-07-14T16:46:02+00:00" }, { "name": "sebastian/cli-parser", @@ -3261,46 +3265,43 @@ }, { "name": "symfony/console", - "version": "v5.4.15", + "version": "v6.1.7", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "ea59bb0edfaf9f28d18d8791410ee0355f317669" + "reference": "a1282bd0c096e0bdb8800b104177e2ce404d8815" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/ea59bb0edfaf9f28d18d8791410ee0355f317669", - "reference": "ea59bb0edfaf9f28d18d8791410ee0355f317669", + "url": "https://api.github.com/repos/symfony/console/zipball/a1282bd0c096e0bdb8800b104177e2ce404d8815", + "reference": "a1282bd0c096e0bdb8800b104177e2ce404d8815", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php73": "^1.9", - "symfony/polyfill-php80": "^1.16", "symfony/service-contracts": "^1.1|^2|^3", - "symfony/string": "^5.1|^6.0" + "symfony/string": "^5.4|^6.0" }, "conflict": { - "psr/log": ">=3", - "symfony/dependency-injection": "<4.4", - "symfony/dotenv": "<5.1", - "symfony/event-dispatcher": "<4.4", - "symfony/lock": "<4.4", - "symfony/process": "<4.4" + "symfony/dependency-injection": "<5.4", + "symfony/dotenv": "<5.4", + "symfony/event-dispatcher": "<5.4", + "symfony/lock": "<5.4", + "symfony/process": "<5.4" }, "provide": { - "psr/log-implementation": "1.0|2.0" + "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { - "psr/log": "^1|^2", - "symfony/config": "^4.4|^5.0|^6.0", - "symfony/dependency-injection": "^4.4|^5.0|^6.0", - "symfony/event-dispatcher": "^4.4|^5.0|^6.0", - "symfony/lock": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/var-dumper": "^4.4|^5.0|^6.0" + "psr/log": "^1|^2|^3", + "symfony/config": "^5.4|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/event-dispatcher": "^5.4|^6.0", + "symfony/lock": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0", + "symfony/var-dumper": "^5.4|^6.0" }, "suggest": { "psr/log": "For using the console logger", @@ -3340,7 +3341,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.15" + "source": "https://github.com/symfony/console/tree/v6.1.7" }, "funding": [ { @@ -3356,29 +3357,29 @@ "type": "tidelift" } ], - "time": "2022-10-26T21:41:52+00:00" + "time": "2022-10-26T21:42:49+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", + "reference": "07f1b9cc2ffee6aaafcf4b710fbc38ff736bd918", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -3407,7 +3408,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.1.1" }, "funding": [ { @@ -3423,7 +3424,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-02-25T11:15:52+00:00" }, { "name": "symfony/polyfill-ctype", @@ -3755,85 +3756,6 @@ ], "time": "2022-11-03T14:55:06+00:00" }, - { - "name": "symfony/polyfill-php73", - "version": "v1.27.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.27-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.27.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2022-11-03T14:55:06+00:00" - }, { "name": "symfony/polyfill-php80", "version": "v1.27.0", @@ -3919,22 +3841,21 @@ }, { "name": "symfony/service-contracts", - "version": "v2.5.2", + "version": "v3.1.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", - "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/925e713fe8fcacf6bc05e936edd8dd5441a21239", + "reference": "925e713fe8fcacf6bc05e936edd8dd5441a21239", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/container": "^1.1", - "symfony/deprecation-contracts": "^2.1|^3" + "php": ">=8.1", + "psr/container": "^2.0" }, "conflict": { "ext-psr": "<1.1|>=2" @@ -3945,7 +3866,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.1-dev" }, "thanks": { "name": "symfony/contracts", @@ -3955,7 +3876,10 @@ "autoload": { "psr-4": { "Symfony\\Contracts\\Service\\": "" - } + }, + "exclude-from-classmap": [ + "/Test/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -3982,7 +3906,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/service-contracts/tree/v3.1.1" }, "funding": [ { @@ -3998,38 +3922,37 @@ "type": "tidelift" } ], - "time": "2022-05-30T19:17:29+00:00" + "time": "2022-05-30T19:18:58+00:00" }, { "name": "symfony/string", - "version": "v5.4.15", + "version": "v6.1.7", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed" + "reference": "823f143370880efcbdfa2dbca946b3358c4707e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/571334ce9f687e3e6af72db4d3b2a9431e4fd9ed", - "reference": "571334ce9f687e3e6af72db4d3b2a9431e4fd9ed", + "url": "https://api.github.com/repos/symfony/string/zipball/823f143370880efcbdfa2dbca946b3358c4707e5", + "reference": "823f143370880efcbdfa2dbca946b3358c4707e5", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.1", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": ">=3.0" + "symfony/translation-contracts": "<2.0" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/translation-contracts": "^2.0|^3.0", + "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", "autoload": { @@ -4068,7 +3991,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.15" + "source": "https://github.com/symfony/string/tree/v6.1.7" }, "funding": [ { @@ -4084,7 +4007,7 @@ "type": "tidelift" } ], - "time": "2022-10-05T15:16:54+00:00" + "time": "2022-10-10T09:34:31+00:00" }, { "name": "theseer/tokenizer", @@ -4415,13 +4338,13 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "~8.0.0 || ~8.1.0" + "php": "~8.1.0" }, "platform-dev": { "ext-phar": "*" }, "platform-overrides": { - "php": "8.0.99" + "php": "8.1.99" }, "plugin-api-version": "2.3.0" } From c1194ac13b0013224363ff5d96738e7069b13f78 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 20:23:15 +0100 Subject: [PATCH 04/53] Removed execution branches that are no longer reachable as per PHP 8.1 Signed-off-by: Marco Pivetta --- composer.json | 5 +---- polyfill/ReflectionEnumPolyfill.php | 14 -------------- src/Generator/EnumGenerator/Cases/CaseFactory.php | 6 ------ src/Generator/EnumGenerator/EnumGenerator.php | 7 ------- src/Generator/PropertyGenerator.php | 3 +-- test/Generator/MethodGeneratorTest.php | 10 +--------- test/Generator/ParameterGeneratorTest.php | 14 ++------------ 7 files changed, 5 insertions(+), 54 deletions(-) delete mode 100644 polyfill/ReflectionEnumPolyfill.php diff --git a/composer.json b/composer.json index 5ad717b4..94671dba 100644 --- a/composer.json +++ b/composer.json @@ -36,10 +36,7 @@ "autoload": { "psr-4": { "Laminas\\Code\\": "src/" - }, - "files": [ - "polyfill/ReflectionEnumPolyfill.php" - ] + } }, "autoload-dev": { "psr-4": { diff --git a/polyfill/ReflectionEnumPolyfill.php b/polyfill/ReflectionEnumPolyfill.php deleted file mode 100644 index 19bd49c6..00000000 --- a/polyfill/ReflectionEnumPolyfill.php +++ /dev/null @@ -1,14 +0,0 @@ -= 80100) { - return; -} - -/** @internal */ -class ReflectionEnum -{ - public function __construct($enum) - { - } -} - diff --git a/src/Generator/EnumGenerator/Cases/CaseFactory.php b/src/Generator/EnumGenerator/Cases/CaseFactory.php index 0e1d5550..48a92f49 100644 --- a/src/Generator/EnumGenerator/Cases/CaseFactory.php +++ b/src/Generator/EnumGenerator/Cases/CaseFactory.php @@ -11,8 +11,6 @@ use function array_map; use function assert; -use const PHP_VERSION_ID; - /** @internal */ final class CaseFactory { @@ -47,10 +45,6 @@ public static function fromOptions(array $options) */ public static function fromReflectionCases(ReflectionEnum $enum) { - if (PHP_VERSION_ID < 80100) { - throw new InvalidArgumentException('This feature only works from PHP 8.1 onwards.'); - } - $backingType = $enum->getBackingType(); if ($backingType === null) { diff --git a/src/Generator/EnumGenerator/EnumGenerator.php b/src/Generator/EnumGenerator/EnumGenerator.php index 23d5e0a0..e730b648 100644 --- a/src/Generator/EnumGenerator/EnumGenerator.php +++ b/src/Generator/EnumGenerator/EnumGenerator.php @@ -2,7 +2,6 @@ namespace Laminas\Code\Generator\EnumGenerator; -use InvalidArgumentException; use Laminas\Code\Generator\EnumGenerator\Cases\BackedCases; use Laminas\Code\Generator\EnumGenerator\Cases\CaseFactory; use Laminas\Code\Generator\EnumGenerator\Cases\PureCases; @@ -11,8 +10,6 @@ use function array_map; use function implode; -use const PHP_VERSION_ID; - /** @psalm-immutable */ final class EnumGenerator { @@ -97,10 +94,6 @@ public static function withConfig(array $options): self public static function fromReflection(ReflectionEnum $enum): self { - if (PHP_VERSION_ID < 80100) { - throw new InvalidArgumentException('This feature only works from PHP 8.1 onwards.'); - } - return new self( Name::fromFullyQualifiedClassName($enum->getName()), CaseFactory::fromReflectionCases($enum), diff --git a/src/Generator/PropertyGenerator.php b/src/Generator/PropertyGenerator.php index 7e25a0cc..b7ff20a9 100644 --- a/src/Generator/PropertyGenerator.php +++ b/src/Generator/PropertyGenerator.php @@ -9,7 +9,6 @@ use function gettype; use function is_bool; use function is_object; -use function method_exists; use function sprintf; use function str_replace; use function strtolower; @@ -75,7 +74,7 @@ public static function fromReflection(PropertyReflection $reflectionProperty) $property->setStatic(true); } - if (method_exists($reflectionProperty, 'isReadonly') && $reflectionProperty->isReadonly()) { + if ($reflectionProperty->isReadonly()) { $property->setReadonly(true); } diff --git a/test/Generator/MethodGeneratorTest.php b/test/Generator/MethodGeneratorTest.php index 96818973..1777ebaa 100644 --- a/test/Generator/MethodGeneratorTest.php +++ b/test/Generator/MethodGeneratorTest.php @@ -25,8 +25,6 @@ use function array_shift; use function array_values; -use const PHP_VERSION_ID; - /** * @group Laminas_Code_Generator * @group Laminas_Code_Generator_Php @@ -436,7 +434,7 @@ public function testFrom($className, $methodName, $expectedReturnSignature) */ public function returnTypeHintClasses() { - $parameters = [ + return [ [ReturnTypeHintedClass::class, 'voidReturn', 'void'], [ReturnTypeHintedClass::class, 'arrayReturn', 'array'], [ReturnTypeHintedClass::class, 'callableReturn', 'callable'], @@ -470,12 +468,6 @@ public function returnTypeHintClasses() [Php80Types::class, 'unionType', '\\' . Php80Types::class . '|\\' . stdClass::class], [Php80Types::class, 'staticType', 'static'], ]; - - return array_values(array_filter( - $parameters, - static fn(array $parameter) => PHP_VERSION_ID >= 80000 - || $parameter[0] !== Php80Types::class - )); } /** diff --git a/test/Generator/ParameterGeneratorTest.php b/test/Generator/ParameterGeneratorTest.php index 88b3afa4..173c9a8e 100644 --- a/test/Generator/ParameterGeneratorTest.php +++ b/test/Generator/ParameterGeneratorTest.php @@ -33,8 +33,6 @@ use function strpos; use function strtolower; -use const PHP_VERSION_ID; - /** * @group Laminas_Code_Generator * @group Laminas_Code_Generator_Php @@ -478,21 +476,13 @@ public function reflectionHints() [ObjectHintsClass::class, 'nullDefaultObjectParameter', 'foo', '?object'], ]; - $compatibleParameters = array_filter( - $parameters, - static fn(array $parameter) => PHP_VERSION_ID >= 70200 - || ( - false === strpos($parameter[3], 'object') - ) - ); - // just re-organizing the keys so that the phpunit data set makes sense in errors: return array_combine( array_map( static fn(array $definition) => $definition[0] . '#' . $definition[1], - $compatibleParameters + $parameters ), - $compatibleParameters + $parameters ); } From d6b1e4d223097549b42966722c4da4e2bdfd0171 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 20:23:53 +0100 Subject: [PATCH 05/53] Refactored `EnumGenerator` internals to leverage PHP 8.1 semantics Signed-off-by: Marco Pivetta --- .../EnumGenerator/Cases/BackedCases.php | 28 +++-------------- .../EnumGenerator/Cases/CaseFactory.php | 31 +++++++++++++------ .../EnumGenerator/Cases/PureCases.php | 18 ++--------- src/Generator/EnumGenerator/EnumGenerator.php | 4 +-- 4 files changed, 30 insertions(+), 51 deletions(-) diff --git a/src/Generator/EnumGenerator/Cases/BackedCases.php b/src/Generator/EnumGenerator/Cases/BackedCases.php index 7a22ea8b..371681e2 100644 --- a/src/Generator/EnumGenerator/Cases/BackedCases.php +++ b/src/Generator/EnumGenerator/Cases/BackedCases.php @@ -14,39 +14,21 @@ */ final class BackedCases { - private string $type; - - /** @var list */ - private array $cases; - /** + * @param 'int'|'string' $type * @param list $cases */ - private function __construct(string $type, array $cases) - { - $this->type = $type; - $this->cases = $cases; - } - - public function getBackedType(): string - { - return $this->type; - } - - /** - * @return list - */ - public function getCases(): array + private function __construct(public readonly string $type, public readonly array $cases) { - return $this->cases; } /** - * @param array|array $backedCases + * @param array|array $backedCases + * @param 'int'|'string' $type */ public static function fromCasesWithType(array $backedCases, string $type): self { - if (in_array($type, ['int', 'string']) === false) { + if (! ($type === 'int' || $type === 'string')) { throw new InvalidArgumentException(sprintf( '"%s" is not a valid type for Enums, only "int" and "string" types are allowed.', $type diff --git a/src/Generator/EnumGenerator/Cases/CaseFactory.php b/src/Generator/EnumGenerator/Cases/CaseFactory.php index 48a92f49..b82ead32 100644 --- a/src/Generator/EnumGenerator/Cases/CaseFactory.php +++ b/src/Generator/EnumGenerator/Cases/CaseFactory.php @@ -2,11 +2,12 @@ namespace Laminas\Code\Generator\EnumGenerator\Cases; -use InvalidArgumentException; use ReflectionEnum; use ReflectionEnumBackedCase; use ReflectionEnumUnitCase; +use ReflectionNamedType; +use function array_combine; use function array_key_exists; use function array_map; use function assert; @@ -48,17 +49,27 @@ public static function fromReflectionCases(ReflectionEnum $enum) $backingType = $enum->getBackingType(); if ($backingType === null) { - $callback = static fn(ReflectionEnumUnitCase $singleCase): string => $singleCase->getName(); - $pureCases = array_map($callback, $enum->getCases()); - - return PureCases::fromCases($pureCases); + return PureCases::fromCases(array_map( + /** @return non-empty-string */ + static fn(ReflectionEnumUnitCase $singleCase): string => $singleCase->getName(), + $enum->getCases() + )); } - $backedCases = []; - foreach ($enum->getCases() as $singleCase) { - $backedCases[$singleCase->getName()] = $singleCase->getBackingValue(); - } + assert($backingType instanceof ReflectionNamedType); + + $cases = $enum->getCases(); - return BackedCases::fromCasesWithType($backedCases, $backingType->getName()); + return BackedCases::fromCasesWithType( + array_combine( + array_map( + /** @return non-empty-string */ + static fn(ReflectionEnumBackedCase $case): string => $case->getName(), + $cases + ), + array_map(static fn(ReflectionEnumBackedCase $case): string|int => $case->getBackingValue(), $cases), + ), + $backingType->getName() + ); } } diff --git a/src/Generator/EnumGenerator/Cases/PureCases.php b/src/Generator/EnumGenerator/Cases/PureCases.php index 49cb4ce7..ca46b4b5 100644 --- a/src/Generator/EnumGenerator/Cases/PureCases.php +++ b/src/Generator/EnumGenerator/Cases/PureCases.php @@ -9,23 +9,9 @@ */ final class PureCases { - /** @var list */ - private array $cases; - - /** - * @param list $cases - */ - private function __construct(array $cases) - { - $this->cases = $cases; - } - - /** - * @return list - */ - public function getCases(): array + /** @param list $cases */ + private function __construct(public readonly array $cases) { - return $this->cases; } /** diff --git a/src/Generator/EnumGenerator/EnumGenerator.php b/src/Generator/EnumGenerator/EnumGenerator.php index e730b648..dbd9f8b1 100644 --- a/src/Generator/EnumGenerator/EnumGenerator.php +++ b/src/Generator/EnumGenerator/EnumGenerator.php @@ -58,7 +58,7 @@ private function retrieveType(): string return ''; } - return ': ' . $this->cases->getBackedType(); + return ': ' . $this->cases->type; } private function retrieveCases(): string @@ -67,7 +67,7 @@ private function retrieveCases(): string '', array_map( fn (string $case): string => self::INDENTATION . 'case ' . $case . ';' . self::LINE_FEED, - $this->cases->getCases() + $this->cases->cases ) ); } From 8032b879e27d151cc9dc245a267929de91cda0bd Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 20:24:59 +0100 Subject: [PATCH 06/53] Corrected inference imprecisions in `ClassGenerator::fromReflection()` around constants This is because we were still using the array-style logic for creating constants inside `ClassGenerator::fromReflection()`: switching to the programmatic API makes things much more readable Signed-off-by: Marco Pivetta --- src/Generator/ClassGenerator.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Generator/ClassGenerator.php b/src/Generator/ClassGenerator.php index 5ebfda11..654b9388 100644 --- a/src/Generator/ClassGenerator.php +++ b/src/Generator/ClassGenerator.php @@ -120,13 +120,13 @@ public static function fromReflection(ClassReflection $classReflection) $constants = []; foreach ($classReflection->getReflectionConstants() as $constReflection) { - $constants[] = [ - 'name' => $constReflection->getName(), - 'value' => $constReflection->getValue(), - 'isFinal' => method_exists($constReflection, 'isFinal') - ? $constReflection->isFinal() - : false, - ]; + $constants[] = new PropertyGenerator( + $constReflection->getName(), + new PropertyValueGenerator($constReflection->getValue()), + $constReflection->isFinal() + ? [PropertyGenerator::FLAG_CONSTANT, PropertyGenerator::FLAG_FINAL] + : [PropertyGenerator::FLAG_CONSTANT] + ); } $cg->addConstants($constants); From 7b43090e26b023abe9233df83a3c3636e7378a2f Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 20:25:17 +0100 Subject: [PATCH 07/53] Adjusted sorting of docblock deprecations Signed-off-by: Marco Pivetta --- src/Reflection/FunctionReflection.php | 6 +++--- src/Reflection/MethodReflection.php | 6 +++--- src/Reflection/ParameterReflection.php | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index bf5121f2..81676566 100644 --- a/src/Reflection/FunctionReflection.php +++ b/src/Reflection/FunctionReflection.php @@ -126,12 +126,12 @@ public function getContents($includeDocBlock = true) /** * Get method prototype * - * @param string $format - * @return array|string - * * @deprecated this method is unreliable, and should not be used: it will be removed in the next major release. * It may crash on parameters with union types, and will return relative types, instead of * FQN references + * + * @param string $format + * @return array|string */ public function getPrototype($format = self::PROTOTYPE_AS_ARRAY) { diff --git a/src/Reflection/MethodReflection.php b/src/Reflection/MethodReflection.php index 1b0be0e9..9a5a460c 100644 --- a/src/Reflection/MethodReflection.php +++ b/src/Reflection/MethodReflection.php @@ -85,12 +85,12 @@ public function getDeclaringClass() /** * Get method prototype * - * @param string $format - * @return array|string - * * @deprecated this method is unreliable, and should not be used: it will be removed in the next major release. * It may crash on parameters with union types, and will return relative types, instead of * FQN references + * + * @param string $format + * @return array|string */ #[ReturnTypeWillChange] public function getPrototype($format = self::PROTOTYPE_AS_ARRAY) diff --git a/src/Reflection/ParameterReflection.php b/src/Reflection/ParameterReflection.php index f68bbdc9..1c53791b 100644 --- a/src/Reflection/ParameterReflection.php +++ b/src/Reflection/ParameterReflection.php @@ -72,11 +72,11 @@ public function getDeclaringFunction() /** * Get parameter type * - * @return string|null - * * @deprecated this method is unreliable, and should not be used: it will be removed in the next major release. * It may crash on parameters with union types, and will return relative types, instead of * FQN references + * + * @return string|null */ public function detectType() { From 3c509cdc8e3a970132be67354b9e33bade301b98 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 20:26:09 +0100 Subject: [PATCH 08/53] Re-generated psalm baseline Note: because psalm has imprecise stubs around ENUM reflection symbols, some issues cannot currently be prevented. Ref: https://github.com/vimeo/psalm/issues/8720 Signed-off-by: Marco Pivetta --- psalm-baseline.xml | 76 +++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 48 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 360883e1..30afebc9 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -257,46 +257,26 @@ new static() + + + $type === 'int' || $type === 'string' + $type === 'string' + + - - $pureCases - - + $backingType->getName() - $enum->getCases() - - - $backedCases - - - $backedCases[$singleCase->getName()] - - - $backedCases[$singleCase->getName()] - $backingType - $singleCase - - - getBackingValue - getName - getName - - - ReflectionEnumUnitCase - - - getBackingType - getCases - getCases - - - - - $enum->getName() - - - getName - + static fn(ReflectionEnumBackedCase $case): string => $case->getName() + static fn(ReflectionEnumBackedCase $case): string|int => $case->getBackingValue() + + + $case->getName() + $singleCase->getName() + + + non-empty-string + non-empty-string + @@ -612,18 +592,16 @@ - + + static fn(ReflectionNamedType $type): string => self::reflectionNamedTypeToString($type, $currentClass) + + allowsNull getName getName getParentClass + getTypes - - - - ReflectionIntersectionType - ReflectionIntersectionType - @@ -1147,6 +1125,11 @@ testSetFlagsWithArray + + + 'bool' + + '' @@ -1541,9 +1524,6 @@ testTypeHintWithValidClassName testTypehintsWithNamespaceInNamepsacedClassReturnTypewithBackslash - - $parameter[3] - From 8935aa302ec8ddcbe255e74a1e122208024770d4 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:09:06 +0100 Subject: [PATCH 09/53] Cleaning up `ParameterReflection` internals to get rid of low-hanging static analysis issues Signed-off-by: Marco Pivetta --- src/Reflection/ParameterReflection.php | 113 ++++++++++++++----------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/src/Reflection/ParameterReflection.php b/src/Reflection/ParameterReflection.php index 1c53791b..216309e9 100644 --- a/src/Reflection/ParameterReflection.php +++ b/src/Reflection/ParameterReflection.php @@ -5,12 +5,15 @@ use Laminas\Code\Reflection\DocBlock\Tag\ParamTag; use ReflectionClass; use ReflectionMethod; +use ReflectionNamedType; use ReflectionParameter; use ReflectionProperty; use ReturnTypeWillChange; +use function assert; use function method_exists; +/** @psalm-immutable */ class ParameterReflection extends ReflectionParameter implements ReflectionInterface { /** @var bool */ @@ -19,16 +22,18 @@ class ParameterReflection extends ReflectionParameter implements ReflectionInter /** * Get declaring class reflection object * - * @return ClassReflection + * @return ClassReflection|null */ #[ReturnTypeWillChange] public function getDeclaringClass() { - $phpReflection = parent::getDeclaringClass(); - $laminasReflection = new ClassReflection($phpReflection->getName()); - unset($phpReflection); - - return $laminasReflection; + $reflection = parent::getDeclaringClass(); + + if (! $reflection) { + return null; + } + + return new ClassReflection($reflection->getName()); } /** @@ -39,15 +44,17 @@ public function getDeclaringClass() #[ReturnTypeWillChange] public function getClass() { - $phpReflectionType = parent::getType(); - if ($phpReflectionType === null) { + $type = parent::getType(); + + if ($type === null) { + return null; + } + + if (! ($type instanceof ReflectionNamedType && ! $type->isBuiltin())) { return null; } - $laminasReflection = new ClassReflection($phpReflectionType->getName()); - unset($phpReflectionType); - - return $laminasReflection; + new ClassReflection($type->getName()); } /** @@ -58,15 +65,13 @@ public function getClass() #[ReturnTypeWillChange] public function getDeclaringFunction() { - $phpReflection = parent::getDeclaringFunction(); - if ($phpReflection instanceof ReflectionMethod) { - $laminasReflection = new MethodReflection($this->getDeclaringClass()->getName(), $phpReflection->getName()); - } else { - $laminasReflection = new FunctionReflection($phpReflection->getName()); + $function = parent::getDeclaringFunction(); + + if ($function instanceof ReflectionMethod) { + return new MethodReflection($function->getDeclaringClass()->getName(), $function->getName()); } - unset($phpReflection); - return $laminasReflection; + return new FunctionReflection($function->getName()); } /** @@ -81,15 +86,18 @@ public function getDeclaringFunction() public function detectType() { if ( - method_exists($this, 'getType') - && null !== ($type = $this->getType()) + null !== ($type = $this->getType()) && $type->isBuiltin() ) { return $type->getName(); } if (null !== $type && $type->getName() === 'self') { - return $this->getDeclaringClass()->getName(); + $declaringClass = $this->getDeclaringClass(); + + assert($declaringClass !== null, 'A parameter called `self` can only exist on a class'); + + return $declaringClass->getName(); } if (($class = $this->getClass()) instanceof ReflectionClass) { @@ -128,44 +136,49 @@ public function toString() return parent::__toString(); } - /** - * @return string - */ - public function __toString() + public function isPublicPromoted(): bool { - return parent::__toString(); - } + $property = $this->promotedProperty(); - /** @psalm-pure */ - public function isPromoted(): bool - { - return parent::isPromoted(); - } + if ($property === null) { + return false; + } - public function isPublicPromoted(): bool - { - return $this->isPromoted() - && $this->getDeclaringClass() - ->getProperty($this->getName()) - ->getModifiers() - & ReflectionProperty::IS_PUBLIC; + return (bool) ($property->getModifiers() & ReflectionProperty::IS_PUBLIC); } public function isProtectedPromoted(): bool { - return $this->isPromoted() - && $this->getDeclaringClass() - ->getProperty($this->getName()) - ->getModifiers() - & ReflectionProperty::IS_PROTECTED; + $property = $this->promotedProperty(); + + if ($property === null) { + return false; + } + + return (bool) ($property->getModifiers() & ReflectionProperty::IS_PROTECTED); } public function isPrivatePromoted(): bool { - return $this->isPromoted() - && $this->getDeclaringClass() - ->getProperty($this->getName()) - ->getModifiers() - & ReflectionProperty::IS_PRIVATE; + $property = $this->promotedProperty(); + + if ($property === null) { + return false; + } + + return (bool) ($property->getModifiers() & ReflectionProperty::IS_PRIVATE); + } + + private function promotedProperty(): ?ReflectionProperty + { + if (! $this->isPromoted()) { + return null; + } + + $declaringClass = $this->getDeclaringClass(); + + assert($declaringClass !== null, 'Promoted properties are always part of a class'); + + return $declaringClass->getProperty($this->getName()); } } From fb722e0e62d715e04abf51771a0a7fc425cf071b Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:09:17 +0100 Subject: [PATCH 10/53] Cleaning up `MethodReflection` internals to get rid of low-hanging static analysis issues Signed-off-by: Marco Pivetta --- src/Reflection/MethodReflection.php | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Reflection/MethodReflection.php b/src/Reflection/MethodReflection.php index 9a5a460c..821178f1 100644 --- a/src/Reflection/MethodReflection.php +++ b/src/Reflection/MethodReflection.php @@ -3,6 +3,7 @@ namespace Laminas\Code\Reflection; use ReflectionMethod as PhpReflectionMethod; +use ReflectionParameter as PhpReflectionParameter; use ReturnTypeWillChange; use function array_key_exists; @@ -169,24 +170,18 @@ public function getPrototype($format = self::PROTOTYPE_AS_ARRAY) /** * Get all method parameter reflection objects * - * @return ParameterReflection[] + * @return list */ #[ReturnTypeWillChange] public function getParameters() { - $phpReflections = parent::getParameters(); - $laminasReflections = []; - while ($phpReflections && ($phpReflection = array_shift($phpReflections))) { - $instance = new ParameterReflection( - [$this->getDeclaringClass()->getName(), $this->getName()], - $phpReflection->getName() - ); - $laminasReflections[] = $instance; - unset($phpReflection); - } - unset($phpReflections); - - return $laminasReflections; + $method = [$this->getDeclaringClass()->getName(), $this->getName()]; + + return array_map( + static fn (PhpReflectionParameter $parameter): ParameterReflection + => new ParameterReflection($method, $parameter->getName()), + parent::getParameters() + ); } /** @@ -372,7 +367,7 @@ protected function extractPrefixedWhitespace($haystack, $position) * * @param array $haystack * @param int $position - * @return bool + * @return bool|void */ protected function isEndingBrace($haystack, $position) { From 6419d21ce06c01b19405226f597f47179901d52b Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:11:44 +0100 Subject: [PATCH 11/53] Deprecate `FunctionReflection#getReturn()`, which was initially abused by `laminas/laminas-server` This method attempted to discover the return type of a function, but in a world where return types didn't exist yet (before PHP 7.0). This method has outlived its usefulness, and is now targeted for removal. Signed-off-by: Marco Pivetta --- src/Reflection/FunctionReflection.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index 81676566..91278522 100644 --- a/src/Reflection/FunctionReflection.php +++ b/src/Reflection/FunctionReflection.php @@ -203,6 +203,10 @@ public function getParameters() * * @throws Exception\InvalidArgumentException * @return DocBlockReflection + * + * @deprecated this method is unreliable, and will be dropped in the next major release. + * If you are attempting to inspect the return type of an expression, please + * use more reliable tools, such as `vimeo/psalm` or `phpstan/phpstan` instead. */ public function getReturn() { From 8f3de551cc5f3e1a446c95c05b45fa683bcd244e Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:21:27 +0100 Subject: [PATCH 12/53] Removed unused import Signed-off-by: Marco Pivetta --- src/Reflection/ParameterReflection.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Reflection/ParameterReflection.php b/src/Reflection/ParameterReflection.php index 216309e9..74cd4022 100644 --- a/src/Reflection/ParameterReflection.php +++ b/src/Reflection/ParameterReflection.php @@ -11,7 +11,6 @@ use ReturnTypeWillChange; use function assert; -use function method_exists; /** @psalm-immutable */ class ParameterReflection extends ReflectionParameter implements ReflectionInterface From ab1312b86c46ec26ef452dc6a664829109e6c1bc Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:22:14 +0100 Subject: [PATCH 13/53] Rewrote `FunctionReflection#getParameters()` to match parent types Signed-off-by: Marco Pivetta --- src/Reflection/FunctionReflection.php | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index 91278522..ba4d8030 100644 --- a/src/Reflection/FunctionReflection.php +++ b/src/Reflection/FunctionReflection.php @@ -3,9 +3,10 @@ namespace Laminas\Code\Reflection; use ReflectionFunction; +use ReflectionParameter; use ReturnTypeWillChange; -use function array_shift; +use function array_map; use function array_slice; use function count; use function file; @@ -181,21 +182,18 @@ public function getPrototype($format = self::PROTOTYPE_AS_ARRAY) /** * Get function parameters * - * @return ParameterReflection[] + * @return list */ #[ReturnTypeWillChange] public function getParameters() { - $phpReflections = parent::getParameters(); - $laminasReflections = []; - while ($phpReflections && ($phpReflection = array_shift($phpReflections))) { - $instance = new ParameterReflection($this->getName(), $phpReflection->getName()); - $laminasReflections[] = $instance; - unset($phpReflection); - } - unset($phpReflections); + $name = $this->getName(); - return $laminasReflections; + return array_map( + static fn (ReflectionParameter $parameter): ParameterReflection + => new ParameterReflection($name, $parameter->getName()), + parent::getParameters() + ); } /** From c7dcbb84f71892e032173673ab678189254891d8 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:25:35 +0100 Subject: [PATCH 14/53] Adjusted parameter name to match parent class parameter name Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/VarTag.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/VarTag.php b/src/Reflection/DocBlock/Tag/VarTag.php index e58ffdf3..5dfbd6a3 100644 --- a/src/Reflection/DocBlock/Tag/VarTag.php +++ b/src/Reflection/DocBlock/Tag/VarTag.php @@ -33,14 +33,14 @@ public function getName(): string /** * {@inheritDoc} */ - public function initialize($tagDocblockLine): void + public function initialize($content): void { $match = []; if ( ! preg_match( '#^([^\$]\S+)?\s*(\$[\S]+)?\s*(.*)$#m', - $tagDocblockLine, + $content, $match ) ) { From d4b761e1f4574fd29b836b8b72970a6e25389d3d Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:27:41 +0100 Subject: [PATCH 15/53] Adjusted parameter name to match parent class parameter name Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/ThrowsTag.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/ThrowsTag.php b/src/Reflection/DocBlock/Tag/ThrowsTag.php index d382ade8..c4908288 100644 --- a/src/Reflection/DocBlock/Tag/ThrowsTag.php +++ b/src/Reflection/DocBlock/Tag/ThrowsTag.php @@ -25,14 +25,11 @@ public function getName() return 'throws'; } - /** - * @param string $tagDocBlockLine - * @return void - */ - public function initialize($tagDocBlockLine) + /** {@inheritDoc} */ + public function initialize($content) { $matches = []; - preg_match('#([\w|\\\]+)(?:\s+(.*))?#', $tagDocBlockLine, $matches); + preg_match('#([\w|\\\]+)(?:\s+(.*))?#', $content, $matches); $this->types = explode('|', $matches[1]); From 373c3eadadb937f42247eb97d189089498248ce3 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:30:55 +0100 Subject: [PATCH 16/53] More precise definition of `ThrowsTag#$description` state Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/ThrowsTag.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/ThrowsTag.php b/src/Reflection/DocBlock/Tag/ThrowsTag.php index c4908288..a7243bd9 100644 --- a/src/Reflection/DocBlock/Tag/ThrowsTag.php +++ b/src/Reflection/DocBlock/Tag/ThrowsTag.php @@ -14,7 +14,7 @@ class ThrowsTag implements TagInterface, PhpDocTypedTagInterface */ protected $types = []; - /** @var string */ + /** @var string|null */ protected $description; /** @@ -57,7 +57,7 @@ public function getTypes() } /** - * @return string + * @return string|null */ public function getDescription() { From 59b3947df317361442657cf4b3106f8539b111d3 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:32:40 +0100 Subject: [PATCH 17/53] Better type definitions around `ReturnTag` Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/ReturnTag.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/ReturnTag.php b/src/Reflection/DocBlock/Tag/ReturnTag.php index d74d705e..2aa1c31d 100644 --- a/src/Reflection/DocBlock/Tag/ReturnTag.php +++ b/src/Reflection/DocBlock/Tag/ReturnTag.php @@ -9,10 +9,10 @@ class ReturnTag implements TagInterface, PhpDocTypedTagInterface { - /** @var array */ + /** @var list */ protected $types = []; - /** @var string */ + /** @var string|null */ protected $description; /** @@ -23,14 +23,11 @@ public function getName() return 'return'; } - /** - * @param string $tagDocBlockLine - * @return void - */ - public function initialize($tagDocBlockLine) + /** {@inheritDoc} */ + public function initialize($content) { $matches = []; - if (! preg_match('#((?:[\w|\\\]+(?:\[\])*\|?)+)(?:\s+(.*))?#s', $tagDocBlockLine, $matches)) { + if (! preg_match('#((?:[\w|\\\]+(?:\[\])*\|?)+)(?:\s+(.*))?#s', $content, $matches)) { return; } @@ -62,7 +59,7 @@ public function getTypes() } /** - * @return string + * @return string|null */ public function getDescription() { From 25c294b965b3622375b27242ae766b98b75a66e0 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:34:27 +0100 Subject: [PATCH 18/53] Better type definitions around `PropertyTag` Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/PropertyTag.php | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/PropertyTag.php b/src/Reflection/DocBlock/Tag/PropertyTag.php index 24e0295b..9e95a3fe 100644 --- a/src/Reflection/DocBlock/Tag/PropertyTag.php +++ b/src/Reflection/DocBlock/Tag/PropertyTag.php @@ -8,16 +8,13 @@ class PropertyTag implements TagInterface, PhpDocTypedTagInterface { - /** - * @var string[] - * @psalm-var list - */ + /** @var list */ protected $types = []; - /** @var string */ + /** @var string|null */ protected $propertyName; - /** @var string */ + /** @var string|null */ protected $description; /** @@ -28,15 +25,11 @@ public function getName() return 'property'; } - /** - * Initializer - * - * @param string $tagDocblockLine - */ - public function initialize($tagDocblockLine) + /** {@inheritDoc} */ + public function initialize($content) { $match = []; - if (! preg_match('#^(.+)?(\$[\S]+)[\s]*(.*)$#m', $tagDocblockLine, $match)) { + if (! preg_match('#^(.+)?(\$[\S]+)[\s]*(.*)$#m', $content, $match)) { return; } @@ -61,7 +54,7 @@ public function initialize($tagDocblockLine) public function getType() { if (empty($this->types)) { - return; + return null; } return $this->types[0]; From 8266966a344d8b1978d69adcd61270a47b06fb98 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:36:09 +0100 Subject: [PATCH 19/53] Better type definitions around `ParamTag` Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/ParamTag.php | 33 +++++++----------------- 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/ParamTag.php b/src/Reflection/DocBlock/Tag/ParamTag.php index 5fc20127..708d7d76 100644 --- a/src/Reflection/DocBlock/Tag/ParamTag.php +++ b/src/Reflection/DocBlock/Tag/ParamTag.php @@ -9,36 +9,27 @@ class ParamTag implements TagInterface, PhpDocTypedTagInterface { - /** - * @var string[] - * @psalm-return list - */ + /** @var list */ protected $types = []; - /** @var string */ + /** @var string|null */ protected $variableName; - /** @var string */ + /** @var string|null */ protected $description; - /** - * @return string - */ + /** @return 'param' */ public function getName() { return 'param'; } - /** - * Initializer - * - * @param string $tagDocBlockLine - */ - public function initialize($tagDocBlockLine) + /** {@inheritDoc} */ + public function initialize($content) { $matches = []; - if (! preg_match('#((?:[\w|\\\]+(?:\[\])*\|?)+)(?:\s+(\$\S+))?(?:\s+(.*))?#s', $tagDocBlockLine, $matches)) { + if (! preg_match('#((?:[\w|\\\]+(?:\[\])*\|?)+)(?:\s+(\$\S+))?(?:\s+(.*))?#s', $content, $matches)) { return; } @@ -75,19 +66,13 @@ public function getTypes() return $this->types; } - /** - * Get parameter name - * - * @return string - */ + /** @return string|null */ public function getVariableName() { return $this->variableName; } - /** - * @return string - */ + /** @return string|null */ public function getDescription() { return $this->description; From d5f1ec198f7ab51a0974522d4710c29df304cadb Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:38:13 +0100 Subject: [PATCH 20/53] Better type definitions around `MethodTag` Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/MethodTag.php | 50 ++++++----------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/MethodTag.php b/src/Reflection/DocBlock/Tag/MethodTag.php index c14c60b8..b4a4fb97 100644 --- a/src/Reflection/DocBlock/Tag/MethodTag.php +++ b/src/Reflection/DocBlock/Tag/MethodTag.php @@ -8,45 +8,30 @@ class MethodTag implements TagInterface, PhpDocTypedTagInterface { - /** - * Return value type - * - * @var string[] - * @psalm-var list - */ + /** @var list */ protected $types = []; - /** @var string */ + /** @var string|null */ protected $methodName; - /** @var string */ + /** @var string|null */ protected $description; - /** - * Is static method - * - * @var bool - */ + /** @var bool */ protected $isStatic = false; - /** - * @return string - */ + /** @return 'method' */ public function getName() { return 'method'; } - /** - * Initializer - * - * @param string $tagDocblockLine - */ - public function initialize($tagDocblockLine) + /** {@inheritDoc} */ + public function initialize($content) { $match = []; - if (! preg_match('#^(static[\s]+)?(.+[\s]+)?(.+\(\))[\s]*(.*)$#m', $tagDocblockLine, $match)) { + if (! preg_match('#^(static[\s]+)?(.+[\s]+)?(.+\(\))[\s]*(.*)$#m', $content, $match)) { return; } @@ -75,7 +60,7 @@ public function initialize($tagDocblockLine) public function getReturnType() { if (empty($this->types)) { - return; + return null; } return $this->types[0]; @@ -87,34 +72,25 @@ public function getTypes() return $this->types; } - /** - * @return string - */ + /** @return string|null */ public function getMethodName() { return $this->methodName; } - /** - * @return null|string - */ + /** @return string|null */ public function getDescription() { return $this->description; } - /** - * @return bool - */ + /** @return bool */ public function isStatic() { return $this->isStatic; } - /** - * @return string - * @psalm-return non-empty-string - */ + /** @return non-empty-string */ public function __toString() { return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . "\n"; From 4eafd0d03aa3a0966e5fb9790c409c2abc61519d Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:39:44 +0100 Subject: [PATCH 21/53] Better type definitions around `LicenseTag` Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/LicenseTag.php | 31 ++++++------------- .../DocBlock/Tag/PhpDocTypedTagInterface.php | 3 +- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/LicenseTag.php b/src/Reflection/DocBlock/Tag/LicenseTag.php index d06ec44d..f9d48821 100644 --- a/src/Reflection/DocBlock/Tag/LicenseTag.php +++ b/src/Reflection/DocBlock/Tag/LicenseTag.php @@ -7,30 +7,24 @@ class LicenseTag implements TagInterface { - /** @var string */ + /** @var string|null */ protected $url; - /** @var string */ + /** @var string|null */ protected $licenseName; - /** - * @return string - */ + /** @return 'license' */ public function getName() { return 'license'; } - /** - * Initializer - * - * @param string $tagDocblockLine - */ - public function initialize($tagDocblockLine) + /** {@inheritDoc} */ + public function initialize($content) { $match = []; - if (! preg_match('#^([\S]*)(?:\s+(.*))?$#m', $tagDocblockLine, $match)) { + if (! preg_match('#^([\S]*)(?:\s+(.*))?$#m', $content, $match)) { return; } @@ -43,26 +37,19 @@ public function initialize($tagDocblockLine) } } - /** - * @return null|string - */ + /** @return null|string */ public function getUrl() { return $this->url; } - /** - * @return null|string - */ + /** @return null|string */ public function getLicenseName() { return $this->licenseName; } - /** - * @return string - * @psalm-return non-empty-string - */ + /** @return non-empty-string */ public function __toString() { return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . "\n"; diff --git a/src/Reflection/DocBlock/Tag/PhpDocTypedTagInterface.php b/src/Reflection/DocBlock/Tag/PhpDocTypedTagInterface.php index 0bf3ce68..dcc8340c 100644 --- a/src/Reflection/DocBlock/Tag/PhpDocTypedTagInterface.php +++ b/src/Reflection/DocBlock/Tag/PhpDocTypedTagInterface.php @@ -7,8 +7,7 @@ interface PhpDocTypedTagInterface /** * Return all types supported by the tag definition * - * @return string[] - * @psalm-return list + * @return list */ public function getTypes(); } From 2abd3930bcb6bdcba4760182f1b9bb3d37a59a14 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:47:34 +0100 Subject: [PATCH 22/53] Better type definitions around `GenericTag` Signed-off-by: Marco Pivetta --- src/Generator/DocBlock/Tag/GenericTag.php | 24 +++++------- src/Reflection/DocBlock/Tag/GenericTag.php | 43 +++++++--------------- 2 files changed, 23 insertions(+), 44 deletions(-) diff --git a/src/Generator/DocBlock/Tag/GenericTag.php b/src/Generator/DocBlock/Tag/GenericTag.php index 5900e973..d9e427c4 100644 --- a/src/Generator/DocBlock/Tag/GenericTag.php +++ b/src/Generator/DocBlock/Tag/GenericTag.php @@ -9,15 +9,15 @@ class GenericTag extends AbstractGenerator implements TagInterface, PrototypeGenericInterface { - /** @var string */ + /** @var string|null */ protected $name; - /** @var string */ + /** @var string|null */ protected $content; /** - * @param string $name - * @param string $content + * @param string|null $name + * @param string|null $content */ public function __construct($name = null, $content = null) { @@ -32,7 +32,7 @@ public function __construct($name = null, $content = null) /** * @param string $name - * @return GenericTag + * @return $this */ public function setName($name) { @@ -40,9 +40,7 @@ public function setName($name) return $this; } - /** - * @return string - */ + /** @return string|null */ public function getName() { return $this->name; @@ -50,7 +48,7 @@ public function getName() /** * @param string $content - * @return GenericTag + * @return $this */ public function setContent($content) { @@ -58,17 +56,13 @@ public function setContent($content) return $this; } - /** - * @return string - */ + /** @return string|null */ public function getContent() { return $this->content; } - /** - * @return string - */ + /** @return non-empty-string */ public function generate() { return '@' . $this->name diff --git a/src/Reflection/DocBlock/Tag/GenericTag.php b/src/Reflection/DocBlock/Tag/GenericTag.php index d79d9f4e..8acc0e49 100644 --- a/src/Reflection/DocBlock/Tag/GenericTag.php +++ b/src/Reflection/DocBlock/Tag/GenericTag.php @@ -9,56 +9,48 @@ class GenericTag implements TagInterface, PrototypeGenericInterface { - /** @var string */ + /** @var string|null */ protected $name; - /** @var string */ + /** @var string|null */ protected $content; - /** @var null|string */ + /** @var string */ protected $contentSplitCharacter; - /** @var array */ + /** @var list */ protected $values = []; /** - * @param string $contentSplitCharacter + * @param string $contentSplitCharacter */ public function __construct($contentSplitCharacter = ' ') { $this->contentSplitCharacter = $contentSplitCharacter; } - /** - * @param string $tagDocBlockLine - * @return void - */ - public function initialize($tagDocBlockLine) + /** {@inheritDoc} */ + public function initialize($content) { - $this->parse($tagDocBlockLine); + $this->parse($content); } - /** - * Get annotation tag name - * - * @return string - */ + /** @return string|null */ public function getName() { return $this->name; } /** - * @param string $name + * @param string $name + * @return void */ public function setName($name) { $this->name = $name; } - /** - * @return string - */ + /** @return string|null */ public function getContent() { return $this->content; @@ -73,15 +65,7 @@ public function returnValue($position) return $this->values[$position]; } - /** - * Serialize to string - * - * Required by Reflector - * - * @todo What should this do? - * @return string - * @psalm-return non-empty-string - */ + /** @return non-empty-string */ public function __toString() { return 'DocBlock Tag [ * @' . $this->name . ' ]' . "\n"; @@ -89,6 +73,7 @@ public function __toString() /** * @param string $docBlockLine + * @return void */ protected function parse($docBlockLine) { From c99a9241cd4c28e744e7367510a9d757ee95265e Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 22:49:32 +0100 Subject: [PATCH 23/53] Better type definitions around `AuthorTag` Signed-off-by: Marco Pivetta --- src/Reflection/DocBlock/Tag/AuthorTag.php | 31 +++++++---------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/Reflection/DocBlock/Tag/AuthorTag.php b/src/Reflection/DocBlock/Tag/AuthorTag.php index 9e5c1b47..f897dea1 100644 --- a/src/Reflection/DocBlock/Tag/AuthorTag.php +++ b/src/Reflection/DocBlock/Tag/AuthorTag.php @@ -7,30 +7,24 @@ class AuthorTag implements TagInterface { - /** @var string */ + /** @var string|null */ protected $authorName; - /** @var string */ + /** @var string|null */ protected $authorEmail; - /** - * @return string - */ + /** @return 'author' */ public function getName() { return 'author'; } - /** - * Initializer - * - * @param string $tagDocblockLine - */ - public function initialize($tagDocblockLine) + /** {@inheritDoc} */ + public function initialize($content) { $match = []; - if (! preg_match('/^([^\<]*)(\<([^\>]*)\>)?(.*)$/u', $tagDocblockLine, $match)) { + if (! preg_match('/^([^\<]*)(\<([^\>]*)\>)?(.*)$/u', $content, $match)) { return; } @@ -43,26 +37,19 @@ public function initialize($tagDocblockLine) } } - /** - * @return null|string - */ + /** @return null|string */ public function getAuthorName() { return $this->authorName; } - /** - * @return null|string - */ + /** @return null|string */ public function getAuthorEmail() { return $this->authorEmail; } - /** - * @return string - * @psalm-return non-empty-string - */ + /** @return non-empty-string */ public function __toString() { return 'DocBlock Tag [ * @' . $this->getName() . ' ]' . "\n"; From fc3d1462585ecc1975cdd5437190deb901efae5d Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 23:15:02 +0100 Subject: [PATCH 24/53] Aligning `ClassReflection` types to PHP's `ReflectionClass` parent signature Signed-off-by: Marco Pivetta --- src/Reflection/ClassReflection.php | 98 +++++++++++-------------- test/Reflection/ClassReflectionTest.php | 9 ++- 2 files changed, 46 insertions(+), 61 deletions(-) diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index a6499afb..3756f6d4 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -3,9 +3,11 @@ namespace Laminas\Code\Reflection; use ReflectionClass; +use ReflectionMethod; +use ReflectionProperty; use ReturnTypeWillChange; -use function array_shift; +use function array_map; use function array_slice; use function array_unshift; use function file; @@ -40,10 +42,9 @@ public function getDocBlock() } /** - * Return the start line of the class + * {@inheritDoc} * - * @param bool $includeDocComment - * @return int + * @param bool $includeDocComment */ #[ReturnTypeWillChange] public function getStartLine($includeDocComment = false) @@ -83,21 +84,15 @@ public function getContents($includeDocBlock = true) /** * Get all reflection objects of implemented interfaces * - * @return ClassReflection[] + * @return array */ #[ReturnTypeWillChange] public function getInterfaces() { - $phpReflections = parent::getInterfaces(); - $laminasReflections = []; - while ($phpReflections && ($phpReflection = array_shift($phpReflections))) { - $instance = new ClassReflection($phpReflection->getName()); - $laminasReflections[] = $instance; - unset($phpReflection); - } - unset($phpReflections); - - return $laminasReflections; + return array_map( + static fn (ReflectionClass $interface): ClassReflection => new ClassReflection($interface->getName()), + parent::getInterfaces() + ); } /** @@ -113,65 +108,56 @@ public function getMethod($name) } /** - * Get reflection objects of all methods + * {@inheritDoc} * * @param int $filter - * @return MethodReflection[] + * + * @return list */ #[ReturnTypeWillChange] public function getMethods($filter = -1) { - $methods = []; - foreach (parent::getMethods($filter) as $method) { - $instance = new MethodReflection($this->getName(), $method->getName()); - $methods[] = $instance; - } + $name = $this->getName(); - return $methods; + return array_map( + static fn (ReflectionMethod $method): MethodReflection => new MethodReflection($name, $method->getName()), + parent::getMethods($filter) + ); } /** - * Returns an array of reflection classes of traits used by this class. + * {@inheritDoc} * - * @return null|array + * @return array */ #[ReturnTypeWillChange] public function getTraits() { - $vals = []; - $traits = parent::getTraits(); - if ($traits === null) { - return; - } - - foreach ($traits as $trait) { - $vals[] = new ClassReflection($trait->getName()); - } - - return $vals; + return array_map( + static fn (ReflectionClass $trait): ClassReflection => new ClassReflection($trait->getName()), + parent::getTraits() + ); } /** - * Get parent reflection class of reflected class + * {@inheritDoc} * - * @return ClassReflection|bool + * @return ClassReflection|false */ #[ReturnTypeWillChange] public function getParentClass() { - $phpReflection = parent::getParentClass(); - if ($phpReflection) { - $laminasReflection = new ClassReflection($phpReflection->getName()); - unset($phpReflection); + $reflection = parent::getParentClass(); - return $laminasReflection; + if (! $reflection) { + return false; } - return false; + return new ClassReflection($reflection->getName()); } /** - * Return reflection property of this class by name + * {@inheritDoc} * * @param string $name * @return PropertyReflection @@ -187,24 +173,22 @@ public function getProperty($name) } /** - * Return reflection properties of this class + * {@inheritDoc} * - * @param int $filter - * @return PropertyReflection[] + * @param int $filter + * + * @return list */ #[ReturnTypeWillChange] public function getProperties($filter = -1) { - $phpReflections = parent::getProperties($filter); - $laminasReflections = []; - while ($phpReflections && ($phpReflection = array_shift($phpReflections))) { - $instance = new PropertyReflection($this->getName(), $phpReflection->getName()); - $laminasReflections[] = $instance; - unset($phpReflection); - } - unset($phpReflections); + $name = $this->getName(); - return $laminasReflections; + return array_map( + static fn (ReflectionProperty $property): PropertyReflection + => new PropertyReflection($name, $property->getName()), + parent::getProperties($filter) + ); } /** diff --git a/test/Reflection/ClassReflectionTest.php b/test/Reflection/ClassReflectionTest.php index 5d576545..40f772d8 100644 --- a/test/Reflection/ClassReflectionTest.php +++ b/test/Reflection/ClassReflectionTest.php @@ -5,6 +5,7 @@ use Laminas\Code\Reflection\ClassReflection; use Laminas\Code\Reflection\MethodReflection; use Laminas\Code\Reflection\PropertyReflection; +use LaminasTest\Code\Reflection\TestAsset\TestTraitClass3; use PHPUnit\Framework\TestCase; use function array_shift; @@ -164,13 +165,13 @@ public function testGetTraits() $reflectionClass = new ClassReflection(TestAsset\TestTraitClass4::class); $traitsArray = $reflectionClass->getTraits(); - self::assertIsArray($traitsArray); + self::assertCount(1, $traitsArray); - self::assertInstanceOf(ClassReflection::class, $traitsArray[0]); + self::assertSame(TestTraitClass3::class, $traitsArray[TestTraitClass3::class]->getName()); $reflectionClass = new ClassReflection(TestAsset\TestSampleClass::class); $traitsArray = $reflectionClass->getTraits(); - self::assertIsArray($traitsArray); - self::assertCount(0, $traitsArray); + + self::assertEmpty($traitsArray); } } From f66517e319f12fb250c6dbe187a0189dac108972 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 23:23:31 +0100 Subject: [PATCH 25/53] Improved `PrototypeClassFactory` internal types Signed-off-by: Marco Pivetta --- src/Generic/Prototype/PrototypeClassFactory.php | 16 ++++++++-------- .../Prototype/PrototypeGenericInterface.php | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Generic/Prototype/PrototypeClassFactory.php b/src/Generic/Prototype/PrototypeClassFactory.php index 1bc85751..eeefcc31 100644 --- a/src/Generic/Prototype/PrototypeClassFactory.php +++ b/src/Generic/Prototype/PrototypeClassFactory.php @@ -21,7 +21,7 @@ */ class PrototypeClassFactory { - /** @var array */ + /** @var array */ protected $prototypes = []; /** @var PrototypeGenericInterface|null */ @@ -30,9 +30,9 @@ class PrototypeClassFactory /** * @param PrototypeInterface[] $prototypes */ - public function __construct($prototypes = [], ?PrototypeGenericInterface $genericPrototype = null) + public function __construct(array $prototypes = [], ?PrototypeGenericInterface $genericPrototype = null) { - foreach ((array) $prototypes as $prototype) { + foreach ($prototypes as $prototype) { $this->addPrototype($prototype); } @@ -44,7 +44,7 @@ public function __construct($prototypes = [], ?PrototypeGenericInterface $generi /** * @throws Exception\InvalidArgumentException */ - public function addPrototype(PrototypeInterface $prototype) + public function addPrototype(PrototypeInterface $prototype): void { $prototypeName = $this->normalizeName($prototype->getName()); @@ -58,7 +58,7 @@ public function addPrototype(PrototypeInterface $prototype) /** * @throws Exception\InvalidArgumentException */ - public function setGenericPrototype(PrototypeGenericInterface $prototype) + public function setGenericPrototype(PrototypeGenericInterface $prototype): void { if (isset($this->genericPrototype)) { throw new Exception\InvalidArgumentException('A default prototype is already set'); @@ -102,10 +102,10 @@ public function getClonedPrototype($prototypeName) if (! $this->hasPrototype($prototypeName)) { $newPrototype = clone $this->genericPrototype; $newPrototype->setName($prototypeName); - } else { - $newPrototype = clone $this->prototypes[$prototypeName]; + + return $newPrototype; } - return $newPrototype; + return clone $this->prototypes[$prototypeName]; } } diff --git a/src/Generic/Prototype/PrototypeGenericInterface.php b/src/Generic/Prototype/PrototypeGenericInterface.php index f2f2372b..d62d0338 100644 --- a/src/Generic/Prototype/PrototypeGenericInterface.php +++ b/src/Generic/Prototype/PrototypeGenericInterface.php @@ -7,6 +7,7 @@ interface PrototypeGenericInterface extends PrototypeInterface { /** * @param string $name + * @return void */ public function setName($name); } From 40d9e7ebb46417db852ea6b0ed15499114f17173 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 23:29:52 +0100 Subject: [PATCH 26/53] Improved `ValueGenerator` internal types Signed-off-by: Marco Pivetta --- src/Generator/ValueGenerator.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Generator/ValueGenerator.php b/src/Generator/ValueGenerator.php index 56251d11..97a504a3 100644 --- a/src/Generator/ValueGenerator.php +++ b/src/Generator/ValueGenerator.php @@ -57,6 +57,7 @@ class ValueGenerator extends AbstractGenerator protected int $arrayDepth = 0; + /** @var self::OUTPUT_* */ protected string $outputMode = self::OUTPUT_MULTIPLE_LINE; /** @var array */ @@ -70,9 +71,9 @@ class ValueGenerator extends AbstractGenerator protected $constants; /** - * @param mixed $value - * @param string $type - * @param string $outputMode + * @param mixed $value + * @param string $type + * @param self::OUTPUT_* $outputMode * @param null|SplArrayObject|StdlibArrayObject $constants */ public function __construct( @@ -449,8 +450,8 @@ public static function escape($input, $quote = true) } /** - * @param string $outputMode - * @return ValueGenerator + * @param self::OUTPUT_* $outputMode + * @return $this */ public function setOutputMode($outputMode) { @@ -459,7 +460,7 @@ public function setOutputMode($outputMode) } /** - * @return string + * @return self::OUTPUT_* */ public function getOutputMode() { From a994a5391d34c2e0cb2509d6edcc99a48d22f86e Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 23:33:57 +0100 Subject: [PATCH 27/53] Deprecating `ValueGenerator#initEnvironmentConstants()` This API is not suitable for maintenance: the `ValueGenerator` attempts to load defined constants into its scope, and then uses them to generate constant expressions (rather than values). This is risky business, and should be avoided: it will be removed in the next major release. Signed-off-by: Marco Pivetta --- src/Generator/ValueGenerator.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/Generator/ValueGenerator.php b/src/Generator/ValueGenerator.php index 97a504a3..4ec3c286 100644 --- a/src/Generator/ValueGenerator.php +++ b/src/Generator/ValueGenerator.php @@ -104,6 +104,11 @@ public function __construct( /** * Init constant list by defined and magic constants + * + * @deprecated this method attempts to make some magic constants work with the value generator, + * but the value generator is not aware of its surrounding, and cannot really + * generate constant expressions. For such a functionality, consider using an AST-based + * code builder instead. */ public function initEnvironmentConstants() { @@ -127,6 +132,11 @@ public function initEnvironmentConstants() * * @param string $constant * @return $this + * + * @deprecated this method attempts to make some magic constants work with the value generator, + * but the value generator is not aware of its surrounding, and cannot really + * generate constant expressions. For such a functionality, consider using an AST-based + * code builder instead. */ public function addConstant($constant) { @@ -140,6 +150,11 @@ public function addConstant($constant) * * @param string $constant * @return bool + * + * @deprecated this method attempts to make some magic constants work with the value generator, + * but the value generator is not aware of its surrounding, and cannot really + * generate constant expressions. For such a functionality, consider using an AST-based + * code builder instead. */ public function deleteConstant($constant) { @@ -154,6 +169,11 @@ public function deleteConstant($constant) * Return constant list * * @return SplArrayObject|StdlibArrayObject + * + * @deprecated this method attempts to make some magic constants work with the value generator, + * but the value generator is not aware of its surrounding, and cannot really + * generate constant expressions. For such a functionality, consider using an AST-based + * code builder instead. */ public function getConstants() { From 638cfda93f9e552dfe744d50b0d86a7335a3aaac Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 23:50:09 +0100 Subject: [PATCH 28/53] Refining `TraitUsageInterface` types Signed-off-by: Marco Pivetta --- src/Generator/TraitUsageInterface.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Generator/TraitUsageInterface.php b/src/Generator/TraitUsageInterface.php index 943255b5..42b55c21 100644 --- a/src/Generator/TraitUsageInterface.php +++ b/src/Generator/TraitUsageInterface.php @@ -70,6 +70,7 @@ public function getTraits(); * Remove a trait by its name * * @param string $traitName + * @return self */ public function removeTrait($traitName); @@ -92,6 +93,7 @@ public function removeTrait($traitName); * @param mixed $method String or Array * @param string $alias * @param null|int $visibility + * @return $this */ public function addTraitAlias($method, $alias, $visibility = null); @@ -120,6 +122,7 @@ public function getTraitAliases(); * @param mixed $method * @param mixed $traitsToReplace + * @return $this */ public function addTraitOverride($method, $traitsToReplace); From 667463f17ef26d4b828c7790d8def9c27aa9f121 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Fri, 18 Nov 2022 23:55:22 +0100 Subject: [PATCH 29/53] Refining `PropertyGenerator` types Signed-off-by: Marco Pivetta --- src/Generator/PropertyGenerator.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Generator/PropertyGenerator.php b/src/Generator/PropertyGenerator.php index b7ff20a9..8241b412 100644 --- a/src/Generator/PropertyGenerator.php +++ b/src/Generator/PropertyGenerator.php @@ -66,8 +66,10 @@ public static function fromReflection(PropertyReflection $reflectionProperty) $property->omitDefaultValue = true; } - if ($reflectionProperty->getDocComment() != '') { - $property->setDocBlock(DocBlockGenerator::fromReflection($reflectionProperty->getDocBlock())); + $docBlock = $reflectionProperty->getDocBlock(); + + if ($docBlock) { + $property->setDocBlock(DocBlockGenerator::fromReflection($docBlock)); } if ($reflectionProperty->isStatic()) { @@ -261,9 +263,9 @@ public function getDefaultValue() } /** - * @param PropertyValueGenerator|mixed $defaultValue - * @param string $defaultValueType - * @param string $defaultValueOutputMode + * @param PropertyValueGenerator|mixed $defaultValue + * @param PropertyValueGenerator::TYPE_* $defaultValueType + * @param PropertyValueGenerator::OUTPUT_* $defaultValueOutputMode * @return static */ public function setDefaultValue( From 993bb94ed5b64d7b64afafa2f66e0d01a5f2548b Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:00:12 +0100 Subject: [PATCH 30/53] Refining `ParameterGenerator` types Signed-off-by: Marco Pivetta --- src/Generator/ParameterGenerator.php | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/Generator/ParameterGenerator.php b/src/Generator/ParameterGenerator.php index aad090c5..d1259e8b 100644 --- a/src/Generator/ParameterGenerator.php +++ b/src/Generator/ParameterGenerator.php @@ -120,9 +120,9 @@ public static function fromArray(array $array) /** * @param ?string $name * @param ?string $type - * @param ?mixed $defaultValue - * @param ?int $position - * @param bool $passByReference + * @param mixed $defaultValue + * @param ?int $position + * @param bool $passByReference */ public function __construct( $name = null, @@ -159,9 +159,7 @@ public function setType($type) return $this; } - /** - * @return string - */ + /** @return string|null */ public function getType() { return $this->type @@ -192,7 +190,7 @@ public function getName() * * Certain variables are difficult to express * - * @param null|bool|string|int|float|array|ValueGenerator $defaultValue + * @param mixed $defaultValue * @return ParameterGenerator */ public function setDefaultValue($defaultValue) @@ -201,10 +199,9 @@ public function setDefaultValue($defaultValue) throw new Exception\InvalidArgumentException('Variadic parameter cannot have a default value'); } - if (! $defaultValue instanceof ValueGenerator) { - $defaultValue = new ValueGenerator($defaultValue); - } - $this->defaultValue = $defaultValue; + $this->defaultValue = $defaultValue instanceof ValueGenerator + ? $defaultValue + : new ValueGenerator($defaultValue); return $this; } From 6c1b2545bc56ee2b03de7bc880b80c9b1ecd9c1d Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:07:22 +0100 Subject: [PATCH 31/53] Refining `InterfaceGenerator` and `MethodGenerator` types Signed-off-by: Marco Pivetta --- src/Generator/ClassGenerator.php | 2 +- src/Generator/InterfaceGenerator.php | 6 ++++-- src/Generator/MethodGenerator.php | 13 +++++-------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/Generator/ClassGenerator.php b/src/Generator/ClassGenerator.php index 654b9388..401d0f43 100644 --- a/src/Generator/ClassGenerator.php +++ b/src/Generator/ClassGenerator.php @@ -583,7 +583,7 @@ public function addConstantFromGenerator(PropertyGenerator $constant) * Add Constant * * @param string $name Non-empty string - * @param string|int|null|float|array $value Scalar + * @param mixed $value Scalar * @throws Exception\InvalidArgumentException * @return static */ diff --git a/src/Generator/InterfaceGenerator.php b/src/Generator/InterfaceGenerator.php index 183c1af1..56011aac 100644 --- a/src/Generator/InterfaceGenerator.php +++ b/src/Generator/InterfaceGenerator.php @@ -34,8 +34,10 @@ public static function fromReflection(ClassReflection $classReflection) $cg->setSourceContent($cg->getSourceContent()); $cg->setSourceDirty(false); - if ($classReflection->getDocComment() != '') { - $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock())); + $docBlock = $classReflection->getDocBlock(); + + if ($docBlock) { + $cg->setDocBlock(DocBlockGenerator::fromReflection($docBlock)); } // set the namespace diff --git a/src/Generator/MethodGenerator.php b/src/Generator/MethodGenerator.php index c8b3d748..12115f23 100644 --- a/src/Generator/MethodGenerator.php +++ b/src/Generator/MethodGenerator.php @@ -4,6 +4,7 @@ use Laminas\Code\Reflection\MethodReflection; +use function array_map; use function explode; use function implode; use function is_array; @@ -366,14 +367,10 @@ public function generate() . ($this->returnsReference ? '& ' : '') . $this->getName() . '('; - $parameters = $this->getParameters(); - if (! empty($parameters)) { - foreach ($parameters as $parameter) { - $parameterOutput[] = $parameter->generate(); - } - - $output .= implode(', ', $parameterOutput); - } + $output .= implode(', ', array_map( + static fn (ParameterGenerator $parameter): string => $parameter->generate(), + $this->getParameters() + )); $output .= ')'; From d5f38865c77694cbe24174c7d87203c7f3c234f6 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:20:39 +0100 Subject: [PATCH 32/53] Refining `FileGenerator` types Signed-off-by: Marco Pivetta --- src/Generator/FileGenerator.php | 34 +++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/Generator/FileGenerator.php b/src/Generator/FileGenerator.php index a541f8fb..05b304d3 100644 --- a/src/Generator/FileGenerator.php +++ b/src/Generator/FileGenerator.php @@ -48,7 +48,7 @@ class FileGenerator extends AbstractGenerator protected string $namespace = ''; - /** @psalm-var list */ + /** @psalm-var list */ protected array $uses = []; /** @@ -219,7 +219,17 @@ public function getUses($withResolvedAs = false) } /** - * @param array $uses + * @param array< + * string|int, + * array{ + * 'use': non-empty-string, + * 'as': non-empty-string|null + * }|array{ + * non-empty-string, + * non-empty-string|null + * }|non-empty-string + * > $uses + * * @return FileGenerator */ public function setUses(array $uses) @@ -227,22 +237,21 @@ public function setUses(array $uses) foreach ($uses as $use) { $use = (array) $use; if (array_key_exists('use', $use) && array_key_exists('as', $use)) { - $import = $use['use']; - $alias = $use['as']; - } elseif (count($use) == 2) { + $this->setUse($use['use'], $use['as']); + } elseif (count($use) === 2) { [$import, $alias] = $use; + + $this->setUse($import, $alias); } else { - $import = current($use); - $alias = null; + $this->setUse(current($use)); } - $this->setUse($import, $alias); } return $this; } /** - * @param string $use - * @param null|string $as + * @param non-empty-string $use + * @param null|non-empty-string $as * @return FileGenerator */ public function setUse($use, $as = null) @@ -504,10 +513,7 @@ public function generate() //build uses array foreach ($classes as $class) { //check for duplicate use statements - $uses = $class->getUses(); - if (! empty($uses) && is_array($uses)) { - $classUses = array_merge($classUses, $uses); - } + $classUses = array_merge($classUses, $class->getUses()); } // process import statements From a18791d247207e9d743a325e89d61e7a48382055 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:23:39 +0100 Subject: [PATCH 33/53] Refining `AbstractTypeableTag` types Signed-off-by: Marco Pivetta --- src/Generator/DocBlock/Tag/AbstractTypeableTag.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Generator/DocBlock/Tag/AbstractTypeableTag.php b/src/Generator/DocBlock/Tag/AbstractTypeableTag.php index db99d0b7..3f4b4271 100644 --- a/src/Generator/DocBlock/Tag/AbstractTypeableTag.php +++ b/src/Generator/DocBlock/Tag/AbstractTypeableTag.php @@ -16,15 +16,15 @@ */ abstract class AbstractTypeableTag extends AbstractGenerator { - /** @var string */ + /** @var string|null */ protected $description; - /** @var array */ + /** @var string[] */ protected $types = []; /** * @param string|string[] $types - * @param string $description + * @param string|null $description */ public function __construct($types = [], $description = null) { @@ -48,7 +48,7 @@ public function setDescription($description) } /** - * @return string + * @return string|null */ public function getDescription() { @@ -59,7 +59,7 @@ public function getDescription() * Array of types or string with types delimited by pipe (|) * e.g. array('int', 'null') or "int|null" * - * @param array|string $types + * @param string[]|string $types * @return AbstractTypeableTag */ public function setTypes($types) @@ -72,7 +72,7 @@ public function setTypes($types) } /** - * @return array + * @return string[] */ public function getTypes() { From 3d86e90e37ac898aeed2771d9d325d8039c126bf Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:26:23 +0100 Subject: [PATCH 34/53] Refining `PropertyTag` types Signed-off-by: Marco Pivetta --- src/Generator/DocBlock/Tag/PropertyTag.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Generator/DocBlock/Tag/PropertyTag.php b/src/Generator/DocBlock/Tag/PropertyTag.php index b881caa0..5dbc23eb 100644 --- a/src/Generator/DocBlock/Tag/PropertyTag.php +++ b/src/Generator/DocBlock/Tag/PropertyTag.php @@ -6,12 +6,12 @@ class PropertyTag extends AbstractTypeableTag implements TagInterface { - /** @var string */ + /** @var string|null */ protected $propertyName; /** * @param string $propertyName - * @param array $types + * @param string[] $types * @param string $description */ public function __construct($propertyName = null, $types = [], $description = null) @@ -42,7 +42,7 @@ public function setPropertyName($propertyName) } /** - * @return string + * @return string|null */ public function getPropertyName() { From ffa2ddaeb5f2b0ff3347cd51a58745af444a4881 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:29:49 +0100 Subject: [PATCH 35/53] Refining `MethodTag` types Signed-off-by: Marco Pivetta --- src/Generator/DocBlock/Tag/MethodTag.php | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/Generator/DocBlock/Tag/MethodTag.php b/src/Generator/DocBlock/Tag/MethodTag.php index c433cb8e..d8c98470 100644 --- a/src/Generator/DocBlock/Tag/MethodTag.php +++ b/src/Generator/DocBlock/Tag/MethodTag.php @@ -6,17 +6,17 @@ class MethodTag extends AbstractTypeableTag implements TagInterface { - /** @var string */ + /** @var string|null */ protected $methodName; /** @var bool */ protected $isStatic = false; /** - * @param string $methodName - * @param array $types - * @param string $description - * @param bool $isStatic + * @param string|null $methodName + * @param string[] $types + * @param string $description + * @param bool $isStatic */ public function __construct($methodName = null, $types = [], $description = null, $isStatic = false) { @@ -56,7 +56,7 @@ public function isStatic() } /** - * @param string $methodName + * @param non-empty-string $methodName * @return MethodTag */ public function setMethodName($methodName) @@ -65,17 +65,13 @@ public function setMethodName($methodName) return $this; } - /** - * @return string - */ + /** @return string|null */ public function getMethodName() { return $this->methodName; } - /** - * @return string - */ + /** @return non-empty-string */ public function generate() { return '@method' From 9ba9cec51df2d6ae30b1c71cee74fd1c51c8d696 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:31:30 +0100 Subject: [PATCH 36/53] Refining `LicenseTag` types Signed-off-by: Marco Pivetta --- src/Generator/DocBlock/Tag/LicenseTag.php | 24 ++++++++--------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/Generator/DocBlock/Tag/LicenseTag.php b/src/Generator/DocBlock/Tag/LicenseTag.php index 8b78d62b..506bb9ce 100644 --- a/src/Generator/DocBlock/Tag/LicenseTag.php +++ b/src/Generator/DocBlock/Tag/LicenseTag.php @@ -8,15 +8,15 @@ class LicenseTag extends AbstractGenerator implements TagInterface { - /** @var string */ + /** @var string|null */ protected $url; - /** @var string */ + /** @var string|null */ protected $licenseName; /** - * @param string $url - * @param string $licenseName + * @param string|null $url + * @param string|null $licenseName */ public function __construct($url = null, $licenseName = null) { @@ -41,9 +41,7 @@ public static function fromReflection(ReflectionTagInterface $reflectionTag) return $tagManager->createTagFromReflection($reflectionTag); } - /** - * @return string - */ + /** @return 'license' */ public function getName() { return 'license'; @@ -59,9 +57,7 @@ public function setUrl($url) return $this; } - /** - * @return string - */ + /** @return string|null */ public function getUrl() { return $this->url; @@ -77,17 +73,13 @@ public function setLicenseName($name) return $this; } - /** - * @return string - */ + /** @return string|null */ public function getLicenseName() { return $this->licenseName; } - /** - * @return string - */ + /** @return non-empty-string */ public function generate() { return '@license' From 9ff6ac1f37cb52385aab1c604d44033c6e4cc178 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:34:06 +0100 Subject: [PATCH 37/53] Refining `AuthorTag` types Signed-off-by: Marco Pivetta --- src/Generator/DocBlock/Tag/AuthorTag.php | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/src/Generator/DocBlock/Tag/AuthorTag.php b/src/Generator/DocBlock/Tag/AuthorTag.php index b94201f3..0d047874 100644 --- a/src/Generator/DocBlock/Tag/AuthorTag.php +++ b/src/Generator/DocBlock/Tag/AuthorTag.php @@ -8,15 +8,15 @@ class AuthorTag extends AbstractGenerator implements TagInterface { - /** @var string */ + /** @var string|null */ protected $authorName; - /** @var string */ + /** @var string|null */ protected $authorEmail; /** - * @param string $authorName - * @param string $authorEmail + * @param string|null $authorName + * @param string|null $authorEmail */ public function __construct($authorName = null, $authorEmail = null) { @@ -41,9 +41,7 @@ public static function fromReflection(ReflectionTagInterface $reflectionTag) return $tagManager->createTagFromReflection($reflectionTag); } - /** - * @return string - */ + /** @return 'author' */ public function getName() { return 'author'; @@ -59,9 +57,7 @@ public function setAuthorEmail($authorEmail) return $this; } - /** - * @return string - */ + /** @return string|null */ public function getAuthorEmail() { return $this->authorEmail; @@ -77,17 +73,13 @@ public function setAuthorName($authorName) return $this; } - /** - * @return string - */ + /** @return string|null */ public function getAuthorName() { return $this->authorName; } - /** - * @return string - */ + /** @return non-empty-string */ public function generate() { return '@author' From 9d367b192f2896e7cca4361fa820f74c007509be Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 00:35:39 +0100 Subject: [PATCH 38/53] Refining `Tag` types Signed-off-by: Marco Pivetta --- src/Generator/DocBlock/Tag.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generator/DocBlock/Tag.php b/src/Generator/DocBlock/Tag.php index b1a254cc..cbbe8cda 100644 --- a/src/Generator/DocBlock/Tag.php +++ b/src/Generator/DocBlock/Tag.php @@ -36,7 +36,7 @@ public function setDescription($description) /** * @deprecated Deprecated in 2.3. Use GenericTag::getContent() instead * - * @return string + * @return string|null */ public function getDescription() { From d73a64ad481d8d67765a1b673713ce6543fa6c2b Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:02:03 +0100 Subject: [PATCH 39/53] Refining `ClassGenerator` and `TraitUsage*` types Signed-off-by: Marco Pivetta --- src/Generator/ClassGenerator.php | 55 ++++++++++----------------- src/Generator/TraitUsageGenerator.php | 21 ++++++---- src/Generator/TraitUsageInterface.php | 25 +++++++----- 3 files changed, 51 insertions(+), 50 deletions(-) diff --git a/src/Generator/ClassGenerator.php b/src/Generator/ClassGenerator.php index 401d0f43..0cd62fe9 100644 --- a/src/Generator/ClassGenerator.php +++ b/src/Generator/ClassGenerator.php @@ -79,9 +79,11 @@ public static function fromReflection(ClassReflection $classReflection) $cg->setSourceContent($cg->getSourceContent()); $cg->setSourceDirty(false); + + $docBlock = $classReflection->getDocBlock(); - if ($classReflection->getDocComment() != '') { - $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock())); + if ($docBlock) { + $cg->setDocBlock(DocBlockGenerator::fromReflection($docBlock)); } $cg->setAbstract($classReflection->isAbstract()); @@ -582,10 +584,11 @@ public function addConstantFromGenerator(PropertyGenerator $constant) /** * Add Constant * - * @param string $name Non-empty string - * @param mixed $value Scalar - * @throws Exception\InvalidArgumentException + * @param non-empty-string $name + * @param mixed $value Scalar + * * @return static + *@throws Exception\InvalidArgumentException */ public function addConstant($name, $value, bool $isFinal = false) { @@ -725,13 +728,7 @@ public function getProperty($propertyName) return false; } - /** - * Add a class to "use" classes - * - * @param string $use - * @param string|null $useAlias - * @return static - */ + /** {@inheritDoc} */ public function addUse($use, $useAlias = null) { $this->traitUsageGenerator->addUse($use, $useAlias); @@ -776,11 +773,7 @@ public function removeUseAlias($use) return $this; } - /** - * Returns the "use" classes - * - * @return array - */ + /** {@inheritDoc} */ public function getUses() { return $this->traitUsageGenerator->getUses(); @@ -828,13 +821,14 @@ public function addMethods(array $methods) /** * Add Method from scalars * - * @param string $name - * @param ParameterGenerator[]|array[]|string[] $parameters - * @param int $flags - * @param string $body - * @param string $docBlock - * @throws Exception\InvalidArgumentException + * @param non-empty-string $name + * @param ParameterGenerator[]|array[]|string[] $parameters + * @param int $flags + * @param string $body + * @param string $docBlock + * * @return static + * @throws Exception\InvalidArgumentException */ public function addMethod( $name, @@ -1044,7 +1038,6 @@ public function generate() } } - $indent = $this->getIndentation(); $output = ''; if (null !== ($namespace = $this->getNamespaceName())) { @@ -1081,7 +1074,7 @@ public function generate() $implemented = $this->getImplementedInterfaces(); if (! empty($implemented)) { - $implemented = array_map([$this, 'generateShortOrCompleteClassname'], $implemented); + $implemented = array_map($this->generateShortOrCompleteClassname(...), $implemented); $output .= ' ' . static::IMPLEMENTS_KEYWORD . ' ' . implode(', ', $implemented); } @@ -1124,18 +1117,16 @@ public function generate() } /** - * @param mixed $value - * @return void * @throws Exception\InvalidArgumentException */ - private function validateConstantValue($value) + private function validateConstantValue(mixed $value): void { if (null === $value || is_scalar($value)) { return; } if (is_array($value)) { - array_walk($value, [$this, 'validateConstantValue']); + array_walk($value, $this->validateConstantValue(...)); return; } @@ -1146,11 +1137,7 @@ private function validateConstantValue($value) )); } - /** - * @param string $fqnClassName - * @return string - */ - private function generateShortOrCompleteClassname($fqnClassName) + private function generateShortOrCompleteClassname(string $fqnClassName): string { $fqnClassName = ltrim($fqnClassName, '\\'); $parts = explode('\\', $fqnClassName); diff --git a/src/Generator/TraitUsageGenerator.php b/src/Generator/TraitUsageGenerator.php index d2d50b5b..de375e7a 100644 --- a/src/Generator/TraitUsageGenerator.php +++ b/src/Generator/TraitUsageGenerator.php @@ -18,20 +18,28 @@ use function sprintf; use function strpos; +/** @psalm-type Visibility = ReflectionMethod::IS_PRIVATE|ReflectionMethod::IS_PROTECTED|ReflectionMethod::IS_PUBLIC */ class TraitUsageGenerator extends AbstractGenerator implements TraitUsageInterface { protected ClassGenerator $classGenerator; /** @psalm-var array Array of trait names */ protected array $traits = []; - - /** @var array Array of trait aliases */ + /** + * @var array< + * non-empty-string, + * array{ + * alias: string, + * visibility: Visibility|null + * } + * > Array of trait aliases + */ protected array $traitAliases = []; /** @var array Array of trait overrides */ protected array $traitOverrides = []; - /** @var array Array of string names */ + /** @var array Array of string names */ protected array $uses = []; public function __construct(ClassGenerator $classGenerator) @@ -54,9 +62,7 @@ public function addUse($use, $useAlias = null) return $this; } - /** - * @inheritDoc - */ + /** {@inheritDoc} */ public function getUses() { return array_values($this->uses); @@ -233,7 +239,6 @@ public function removeTrait($traitName) */ public function addTraitAlias($method, $alias, $visibility = null) { - $traitAndMethod = $method; if (is_array($method)) { if (! array_key_exists('traitName', $method)) { throw new Exception\InvalidArgumentException('Missing required argument "traitName" for $method'); @@ -244,6 +249,8 @@ public function addTraitAlias($method, $alias, $visibility = null) } $traitAndMethod = $method['traitName'] . '::' . $method['method']; + } else { + $traitAndMethod = $method; } // Validations diff --git a/src/Generator/TraitUsageInterface.php b/src/Generator/TraitUsageInterface.php index 42b55c21..010711a8 100644 --- a/src/Generator/TraitUsageInterface.php +++ b/src/Generator/TraitUsageInterface.php @@ -2,13 +2,16 @@ namespace Laminas\Code\Generator; +use ReflectionMethod; + interface TraitUsageInterface { /** * Add a class to "use" classes * - * @param string $use - * @param string|null $useAlias + * @param non-empty-string $use + * @param non-empty-string|null $useAlias + * * @return self */ public function addUse($use, $useAlias = null); @@ -16,7 +19,7 @@ public function addUse($use, $useAlias = null); /** * Returns the "use" classes * - * @return array + * @return list */ public function getUses(); @@ -87,18 +90,22 @@ public function removeTrait($traitName); * $alias: * Alias is a string representing the new method name. * - * $visibilty: - * ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PRIVATE | ReflectionMethod::IS_PROTECTED + * @param array{traitName: non-empty-string, method: non-empty-string}|non-empty-string $method + * @param non-empty-string $alias + * @param ReflectionMethod::IS_PUBLIC|ReflectionMethod::IS_PRIVATE|ReflectionMethod::IS_PROTECTED|null $visibility * - * @param mixed $method String or Array - * @param string $alias - * @param null|int $visibility * @return $this */ public function addTraitAlias($method, $alias, $visibility = null); /** - * @return array + * @return array< + * non-empty-string, + * array{ + * alias: string, + * visibility: ReflectionMethod::IS_PRIVATE|ReflectionMethod::IS_PROTECTED|ReflectionMethod::IS_PUBLIC|null + * } + * > */ public function getTraitAliases(); From fec8485b9473144f8e64cb43cc48652d0647f063 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:05:45 +0100 Subject: [PATCH 40/53] Replacing `is_object($v) ? get_class($v) : gettype($v)` ternaries with `get_debug_type()` Signed-off-by: Marco Pivetta --- src/Generator/AbstractGenerator.php | 6 ++---- src/Generator/ClassGenerator.php | 4 ++-- src/Generator/PropertyGenerator.php | 10 +++------- src/Generator/ValueGenerator.php | 4 ++-- 4 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/Generator/AbstractGenerator.php b/src/Generator/AbstractGenerator.php index c1baaf7e..27c05cd2 100644 --- a/src/Generator/AbstractGenerator.php +++ b/src/Generator/AbstractGenerator.php @@ -4,10 +4,8 @@ use Traversable; -use function get_class; -use function gettype; use function is_array; -use function is_object; +use function get_debug_type; use function method_exists; use function sprintf; @@ -103,7 +101,7 @@ public function setOptions($options) throw new Exception\InvalidArgumentException(sprintf( '%s expects an array or Traversable object; received "%s"', __METHOD__, - is_object($options) ? get_class($options) : gettype($options) + get_debug_type($options) )); } diff --git a/src/Generator/ClassGenerator.php b/src/Generator/ClassGenerator.php index 0cd62fe9..12892eb8 100644 --- a/src/Generator/ClassGenerator.php +++ b/src/Generator/ClassGenerator.php @@ -11,7 +11,7 @@ use function array_values; use function array_walk; use function explode; -use function gettype; +use function get_debug_type; use function implode; use function in_array; use function is_array; @@ -1133,7 +1133,7 @@ private function validateConstantValue(mixed $value): void throw new Exception\InvalidArgumentException(sprintf( 'Expected value for constant, value must be a "scalar" or "null", "%s" found', - gettype($value) + get_debug_type($value) )); } diff --git a/src/Generator/PropertyGenerator.php b/src/Generator/PropertyGenerator.php index 8241b412..19299481 100644 --- a/src/Generator/PropertyGenerator.php +++ b/src/Generator/PropertyGenerator.php @@ -5,10 +5,8 @@ use Laminas\Code\Reflection\PropertyReflection; use function array_reduce; -use function get_class; -use function gettype; +use function get_debug_type; use function is_bool; -use function is_object; use function sprintf; use function str_replace; use function strtolower; @@ -165,9 +163,7 @@ public static function fromArray(array $array) '%s is expecting boolean on key %s. Got %s', __METHOD__, $name, - is_object($value) - ? get_class($value) - : gettype($value) + get_debug_type($value) )); } @@ -180,7 +176,7 @@ public static function fromArray(array $array) __METHOD__, TypeGenerator::class, $name, - is_object($value) ? get_class($value) : gettype($value) + get_debug_type($value) )); } $property->setType($value); diff --git a/src/Generator/ValueGenerator.php b/src/Generator/ValueGenerator.php index 4ec3c286..c2a7a548 100644 --- a/src/Generator/ValueGenerator.php +++ b/src/Generator/ValueGenerator.php @@ -11,7 +11,7 @@ use function array_merge; use function array_search; use function count; -use function get_class; +use function get_debug_type; use function get_defined_constants; use function gettype; use function implode; @@ -443,7 +443,7 @@ public function generate() default: throw new Exception\RuntimeException(sprintf( 'Type "%s" is unknown or cannot be used as property default value.', - is_object($value) ? get_class($value) : gettype($value) + get_debug_type($value) )); } From 78d7f8095962fa89bae7f1c2ff410f4c3971e9c0 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:08:28 +0100 Subject: [PATCH 41/53] Regenerated psalm baseline with the now in place type improvements coming with PHP 8.1 Signed-off-by: Marco Pivetta --- psalm-baseline.xml | 459 ++++++++++----------------------------------- 1 file changed, 97 insertions(+), 362 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 30afebc9..1302f32c 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -15,9 +15,6 @@ - - gettype($options) - $optionName $optionValue @@ -29,9 +26,6 @@ (bool) $isSourceDirty (string) $indentation - - is_object($options) - @@ -44,6 +38,10 @@ + + $method + $name + DocBlockGenerator::fromArray($value) @@ -52,17 +50,9 @@ is_string($name) is_string($name) - - [$this, 'validateConstantValue'] - string - - addTraitAlias - addTraitOverride - removeTrait - $array['name'] $value @@ -80,29 +70,22 @@ $name - - $use + $value - - $use + static::IMPLEMENTS_KEYWORD static::OBJECT_TYPE $this->traitUsageGenerator->getUseAlias($fqnClassName) - - $classReflection->getDocBlock() + strrpos($name, '\\') strrpos($name, '\\') - - getInterfaces - getName - $namespaceAlias @@ -113,31 +96,14 @@ new static($array['name']) new static($classReflection->getName()) - - $indent - - + $tagManager->createTagFromReflection($reflectionTag) - $this->setContent($description) - - Tag + Tag - - Tag - Tag - - - - - $this->types - - - $description - @@ -146,16 +112,15 @@ AuthorTag - - $authorEmail - $authorName - - - $content - $name - + + $this + string|null + + + $this->name + @@ -164,19 +129,8 @@ ReturnTag - - $licenseName - $url - - - $types - - - $methodName - MethodTag - (bool) $isStatic @@ -193,18 +147,8 @@ ParamTag ParamTag - + $variableName - ParamTag - - - - - $types - - - $propertyName - PropertyTag @@ -216,19 +160,6 @@ ReturnTag ReturnTag - - ReturnTag - - - - - ThrowsTag - - - - - VarTag - @@ -296,9 +227,7 @@ $value - - $alias - $import + $value $value $value @@ -309,38 +238,39 @@ $name $name - - $alias - $import - $import - $use + $value + + current($use) + + + $alias + $import + (string) $body (string) $filename (string) $namespace - - ! empty($uses) && is_array($uses) - is_array($uses) - new static() + + $name + DocBlockGenerator::fromArray($value) - + $array['name'] $value $value $value $value $value - $value $name @@ -349,9 +279,6 @@ $value $value - - $classReflection->getDocBlock() - new static($array['name']) new static($classReflection->getName()) @@ -362,9 +289,8 @@ DocBlockGenerator::fromArray($value) ParameterGenerator::fromArray($parameter) - + $array['name'] - $parameterOutput $value $value $value @@ -379,18 +305,12 @@ $name - - $parameterOutput[] - $value $reflectionMethod->getDocBlock() - - $parameterOutput - (bool) $returnsReference @@ -400,14 +320,8 @@ - - string - - + $array['name'] - $defaultValue - $reflectionParameter->getDefaultValue() - $value $value $value $value @@ -422,7 +336,6 @@ $value - (bool) $passedByReference (bool) $variadic @@ -454,9 +367,6 @@ $defaultValue - - $reflectionProperty->getDocBlock() - new static($array['name']) new static() @@ -489,81 +399,46 @@ - + is_string($alias) - - addTraitAlias - addTraitOverride - removeTrait - - - $alias['alias'] - $alias['alias'] - $alias['visibility'] + $method $this->traitOverrides[$method] $this->traitOverrides[$traitAndMethod] $traitAndMethod $traitAndMethod $traitAndMethod - $traitAndMethod - $traitAndMethod - $value - $value - $value - $value - - $key - $key + $traits - - $alias['alias'] - $alias['alias'] - $alias['alias'] - $alias['visibility'] - $alias['visibility'] + $this->traitOverrides[$method][$key] $this->traitOverrides[$traitAndMethod][] - - $this->traitAliases[$traitAndMethod] + $this->traitOverrides[$method][$key] $this->traitOverrides[$traitAndMethod] $this->traitOverrides[$traitAndMethod] $this->traitOverrides[$traitAndMethod] - $this->uses[$value] - $this->uses[$value] $this->traitOverrides[$traitAndMethod] - - $alias + $alias $insteadof $insteadofTrait $insteadofTraits $key $traitAndMethod - $traitAndMethod $traitToRemove - $value - $value - $value - $value - $value - $value - - $alias['alias'] + $insteadofTrait - $method['method'] - $method['traitName'] addTraitOverride @@ -584,13 +459,6 @@ $method - - - addTraitAlias - addTraitOverride - removeTrait - - static fn(ReflectionNamedType $type): string => self::reflectionNamedTypeToString($type, $currentClass) @@ -604,6 +472,9 @@ + + getConstants + $constants instanceof StdlibArrayObject @@ -634,17 +505,9 @@ - - addPrototype - setGenericPrototype - - - $newPrototype + $newPrototype - - clone $this->prototypes[$prototypeName] - PrototypeInterface @@ -657,145 +520,32 @@ clone $this->genericPrototype - - (array) $prototypes - - - - - setName - - - parent::getStartLine() - - - ClassReflection|bool - - - int - Exception\ExceptionInterface - - ClassReflection[] - MethodReflection[] - PropertyReflection[] - null|array - $lines + + $startnum + + + $startnum + $this->getStartLine() + getStartLine - - $traits === null - - - - - $authorEmail - $authorName - - - $tagDocblockLine - - - parse - setName - - - string - - - $this->values[$position] - - - $tagDocBlockLine - - - $this->contentSplitCharacter - - - $content - $name - - - - - $licenseName - $url - - - $tagDocblockLine - - - - - $description - $methodName - - - $tagDocblockLine - - - - - $description - $variableName - - - $this->types - getTypes - - - $tagDocBlockLine - - - - - $description - $propertyName - - - $tagDocblockLine - - - - - $description - - - string - - - $this->types[0] - - - $this->types - getTypes - - - $tagDocBlockLine - - - - - $description - - - $tagDocBlockLine - - - - - $tagDocblockLine - + + string|null + + + $this->name + @@ -857,9 +607,6 @@ detectType - - ParameterReflection[] - $returnTypes $returnTypes @@ -903,12 +650,6 @@ detectType - - bool - - - ParameterReflection[] - $haystack[$i][0] $haystack[$i][0] @@ -945,36 +686,29 @@ - $phpReflection->getName() + $function->getName() - - isPromoted + + getDeclaringClass + getDocBlock + getModifiers + getModifiers + getModifiers + getName + getName + getName + getName + getName + getName + getProperty + getTags - - #[ReturnTypeWillChange] - #[ReturnTypeWillChange] - #[ReturnTypeWillChange] - ReflectionParameter - public function __toString() - - - $phpReflectionType->getName() - string|null - - getName - $type->getName() - - getName - - - $type - getName getName @@ -1141,20 +875,19 @@ ['Class1', 'Class2'] - - $resource + + '' + 'public' + 'public' ExceptionInterface::class [] new ClassGenerator() - new stdClass() [] new ClassGenerator() - - 'public' - 'public' + true true true @@ -1171,11 +904,7 @@ FooClass::class FooClass::class - - $aliases['myTrait::method']['alias'] - $aliases['myTrait::method']['alias'] - $aliases['myTrait::method']['visibility'] - $aliases['myTrait::method']['visibility'] + $overrides['myTrait::foo'][0] $overrides['myTrait::foo'][1] $overrides['myTrait::foo'][1] @@ -1396,6 +1125,9 @@ + + $file->getUses() + testClassNotFoundException testConstruction @@ -1526,6 +1258,9 @@ + + $type + new stdClass() @@ -1616,11 +1351,6 @@ type - - - setName - - someFunction @@ -1650,11 +1380,6 @@ bool - - - TypeableTag - - 'LaminasTest_Code_NsTest_BarClass' @@ -1677,6 +1402,13 @@ + + getConstants + getConstants + initEnvironmentConstants + initEnvironmentConstants + initEnvironmentConstants + $constants @@ -1732,12 +1464,15 @@ testPropertyReturns testStartLine - + $parent - - + + getName - + + + $traitsArray[TestTraitClass3::class] + From 214569464f5c4bb174f0a957109b986cdc1b611c Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:17:29 +0100 Subject: [PATCH 42/53] Rewrote `ParameterReflection#getClass()` to match previous behavior Typo caused all tests to start failing. Signed-off-by: Marco Pivetta --- src/Reflection/ParameterReflection.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Reflection/ParameterReflection.php b/src/Reflection/ParameterReflection.php index 74cd4022..3ab4f5f0 100644 --- a/src/Reflection/ParameterReflection.php +++ b/src/Reflection/ParameterReflection.php @@ -45,15 +45,11 @@ public function getClass() { $type = parent::getType(); - if ($type === null) { - return null; - } - if (! ($type instanceof ReflectionNamedType && ! $type->isBuiltin())) { return null; } - new ClassReflection($type->getName()); + return new ClassReflection($type->getName()); } /** From 6e5e3e26b3588c8c1ea3621ef62287b8b27b427a Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:18:56 +0100 Subject: [PATCH 43/53] Since we now use `get_debug_type()` for some errors, adjusting associated test expectations Signed-off-by: Marco Pivetta --- test/Generator/ValueGeneratorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Generator/ValueGeneratorTest.php b/test/Generator/ValueGeneratorTest.php index 1631a264..6d0ea0d1 100644 --- a/test/Generator/ValueGeneratorTest.php +++ b/test/Generator/ValueGeneratorTest.php @@ -479,7 +479,7 @@ public function getEscapedParameters() public function invalidValue(): Generator { yield 'object' => [new DateTime(), DateTime::class]; - yield 'resource' => [fopen('php://input', 'r'), 'resource']; + yield 'resource' => [fopen('php://input', 'r'), 'resource (stream)']; } /** From 52f2c243ac7478dd997cc2cbf87b2fe38f528489 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:20:45 +0100 Subject: [PATCH 44/53] Using CI setup that we use in all other repositories Signed-off-by: Marco Pivetta --- .github/workflows/coding-standards.yml | 56 --------------- .github/workflows/docs-build.yml | 7 +- .github/workflows/phpunit.yml | 60 ---------------- .github/workflows/psalm.yml | 56 --------------- .../workflows/release-on-milestone-closed.yml | 68 ++----------------- 5 files changed, 9 insertions(+), 238 deletions(-) delete mode 100644 .github/workflows/coding-standards.yml delete mode 100644 .github/workflows/phpunit.yml delete mode 100644 .github/workflows/psalm.yml diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml deleted file mode 100644 index e1292130..00000000 --- a/.github/workflows/coding-standards.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: "Check Coding Standards" - -on: - pull_request: - push: - -jobs: - coding-standards: - name: "Check Coding Standards" - - runs-on: ${{ matrix.operating-system }} - - strategy: - matrix: - dependencies: - - "locked" - php-version: - - "7.4" - operating-system: - - "ubuntu-latest" - - steps: - - name: "Checkout" - uses: "actions/checkout@v3" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "pcov" - php-version: "${{ matrix.php-version }}" - ini-values: memory_limit=-1 - tools: composer:v2, cs2pr - - - name: "Cache dependencies" - uses: "actions/cache@v3" - with: - path: | - ~/.composer/cache - vendor - key: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" - restore-keys: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" - - - name: "Install lowest dependencies" - if: ${{ matrix.dependencies == 'lowest' }} - run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" - - - name: "Install highest dependencies" - if: ${{ matrix.dependencies == 'highest' }} - run: "composer update --no-interaction --no-progress --no-suggest" - - - name: "Install locked dependencies" - if: ${{ matrix.dependencies == 'locked' }} - run: "composer install --no-interaction --no-progress --no-suggest" - - - name: "Coding Standard" - run: "vendor/bin/phpcs -q --report=checkstyle | cs2pr" diff --git a/.github/workflows/docs-build.yml b/.github/workflows/docs-build.yml index 24447429..a0630748 100644 --- a/.github/workflows/docs-build.yml +++ b/.github/workflows/docs-build.yml @@ -3,8 +3,7 @@ name: docs-build on: release: types: [published] - repository_dispatch: - types: docs-build + workflow_dispatch: jobs: build-deploy: @@ -13,5 +12,5 @@ jobs: - name: Build Docs uses: laminas/documentation-theme/github-actions/docs@master env: - "DOCS_DEPLOY_KEY": ${{ secrets.DOCS_DEPLOY_KEY }} - "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} + DOCS_TOKEN: ${{ secrets.ORGANIZATION_ADMIN_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml deleted file mode 100644 index 62296047..00000000 --- a/.github/workflows/phpunit.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: "PHPUnit tests" - -on: - pull_request: - push: - -jobs: - phpunit: - name: "PHPUnit tests" - - runs-on: ${{ matrix.operating-system }} - - strategy: - matrix: - dependencies: - - "lowest" - - "highest" - - "locked" - php-version: - - "7.4" - - "8.0" - - "8.1" - operating-system: - - "ubuntu-latest" - - steps: - - name: "Checkout" - uses: "actions/checkout@v3" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "pcov" - php-version: "${{ matrix.php-version }}" - ini-values: memory_limit=-1 - tools: composer:v2, cs2pr - - - name: "Cache dependencies" - uses: "actions/cache@v3" - with: - path: | - ~/.composer/cache - vendor - key: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" - restore-keys: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" - - - name: "Install lowest dependencies" - if: ${{ matrix.dependencies == 'lowest' }} - run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" - - - name: "Install highest dependencies" - if: ${{ matrix.dependencies == 'highest' }} - run: "composer update --no-interaction --no-progress --no-suggest" - - - name: "Install locked dependencies" - if: ${{ matrix.dependencies == 'locked' }} - run: "composer install --no-interaction --no-progress --no-suggest" - - - name: "Tests" - run: "vendor/bin/phpunit" diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml deleted file mode 100644 index cbf903e3..00000000 --- a/.github/workflows/psalm.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: "Static Analysis by Psalm" - -on: - pull_request: - push: - -jobs: - static-analysis-psalm: - name: "Static Analysis by Psalm" - - runs-on: ${{ matrix.operating-system }} - - strategy: - matrix: - dependencies: - - "locked" - php-version: - - "8.1" - operating-system: - - "ubuntu-latest" - - steps: - - name: "Checkout" - uses: "actions/checkout@v3" - - - name: "Install PHP" - uses: "shivammathur/setup-php@v2" - with: - coverage: "pcov" - php-version: "${{ matrix.php-version }}" - ini-values: memory_limit=-1 - tools: composer:v2, cs2pr - - - name: "Cache dependencies" - uses: "actions/cache@v3" - with: - path: | - ~/.composer/cache - vendor - key: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" - restore-keys: "php-${{ matrix.php-version }}-${{ matrix.dependencies }}" - - - name: "Install lowest dependencies" - if: ${{ matrix.dependencies == 'lowest' }} - run: "composer update --prefer-lowest --no-interaction --no-progress --no-suggest" - - - name: "Install highest dependencies" - if: ${{ matrix.dependencies == 'highest' }} - run: "composer update --no-interaction --no-progress --no-suggest" - - - name: "Install locked dependencies" - if: ${{ matrix.dependencies == 'locked' }} - run: "composer install --no-interaction --no-progress --no-suggest" - - - name: "psalm" - run: "vendor/bin/psalm --output-format=github --shepherd --stats" diff --git a/.github/workflows/release-on-milestone-closed.yml b/.github/workflows/release-on-milestone-closed.yml index 62bcfe90..350ec35e 100644 --- a/.github/workflows/release-on-milestone-closed.yml +++ b/.github/workflows/release-on-milestone-closed.yml @@ -1,9 +1,3 @@ -# Alternate workflow example. -# This one is identical to the one in release-on-milestone.yml, with one change: -# the Release step uses the ORGANIZATION_ADMIN_TOKEN instead, to allow it to -# trigger a release workflow event. This is useful if you have other actions -# that intercept that event. - name: "Automatic Releases" on: @@ -13,59 +7,9 @@ on: jobs: release: - name: "GIT tag, release & create merge-up PR" - runs-on: ubuntu-latest - - steps: - - name: "Checkout" - uses: "actions/checkout@v3" - - - name: "Release" - uses: "laminas/automatic-releases@v1" - with: - command-name: "laminas:automatic-releases:release" - env: - "GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - - - name: "Create Merge-Up Pull Request" - uses: "laminas/automatic-releases@v1" - with: - command-name: "laminas:automatic-releases:create-merge-up-pull-request" - env: - "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - - - name: "Create and/or Switch to new Release Branch" - uses: "laminas/automatic-releases@v1" - with: - command-name: "laminas:automatic-releases:switch-default-branch-to-next-minor" - env: - "GITHUB_TOKEN": ${{ secrets.ORGANIZATION_ADMIN_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - - - name: "Bump Changelog Version On Originating Release Branch" - uses: "laminas/automatic-releases@v1" - with: - command-name: "laminas:automatic-releases:bump-changelog" - env: - "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} - - - name: "Create new milestones" - uses: "laminas/automatic-releases@v1" - with: - command-name: "laminas:automatic-releases:create-milestones" - env: - "GITHUB_TOKEN": ${{ secrets.GITHUB_TOKEN }} - "SIGNING_SECRET_KEY": ${{ secrets.SIGNING_SECRET_KEY }} - "GIT_AUTHOR_NAME": ${{ secrets.GIT_AUTHOR_NAME }} - "GIT_AUTHOR_EMAIL": ${{ secrets.GIT_AUTHOR_EMAIL }} + uses: laminas/workflow-automatic-releases/.github/workflows/release-on-milestone-closed.yml@1.x + secrets: + GIT_AUTHOR_EMAIL: ${{ secrets.GIT_AUTHOR_EMAIL }} + GIT_AUTHOR_NAME: ${{ secrets.GIT_AUTHOR_NAME }} + ORGANIZATION_ADMIN_TOKEN: ${{ secrets.ORGANIZATION_ADMIN_TOKEN }} + SIGNING_SECRET_KEY: ${{ secrets.SIGNING_SECRET_KEY }} From 172ce5809ce99babdaa17f2e42c4587ee5912269 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:22:23 +0100 Subject: [PATCH 45/53] Added default Laminas CI setup Signed-off-by: Marco Pivetta --- .github/workflows/continuous-integration.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/continuous-integration.yml diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml new file mode 100644 index 00000000..26c58025 --- /dev/null +++ b/.github/workflows/continuous-integration.yml @@ -0,0 +1,11 @@ +name: "Continuous Integration" + +on: + pull_request: + push: + branches: + tags: + +jobs: + ci: + uses: laminas/workflow-continuous-integration/.github/workflows/continuous-integration.yml@1.x From a3620910bac4f4b67abdf589739d32a16bd9a4be Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:24:36 +0100 Subject: [PATCH 46/53] Applied automated CS fixes Signed-off-by: Marco Pivetta --- src/Generator/AbstractGenerator.php | 2 +- src/Generator/ClassGenerator.php | 6 ++---- src/Generator/FileGenerator.php | 1 - src/Generator/TraitUsageInterface.php | 2 -- src/Generator/ValueGenerator.php | 18 +++++++++--------- .../Prototype/PrototypeClassFactory.php | 2 +- src/Reflection/ClassReflection.php | 2 -- src/Reflection/FunctionReflection.php | 6 +++--- src/Reflection/MethodReflection.php | 3 ++- src/Reflection/ParameterReflection.php | 8 ++++---- 10 files changed, 22 insertions(+), 28 deletions(-) diff --git a/src/Generator/AbstractGenerator.php b/src/Generator/AbstractGenerator.php index 27c05cd2..bce234e1 100644 --- a/src/Generator/AbstractGenerator.php +++ b/src/Generator/AbstractGenerator.php @@ -4,8 +4,8 @@ use Traversable; -use function is_array; use function get_debug_type; +use function is_array; use function method_exists; use function sprintf; diff --git a/src/Generator/ClassGenerator.php b/src/Generator/ClassGenerator.php index 12892eb8..c428805b 100644 --- a/src/Generator/ClassGenerator.php +++ b/src/Generator/ClassGenerator.php @@ -79,7 +79,7 @@ public static function fromReflection(ClassReflection $classReflection) $cg->setSourceContent($cg->getSourceContent()); $cg->setSourceDirty(false); - + $docBlock = $classReflection->getDocBlock(); if ($docBlock) { @@ -586,9 +586,8 @@ public function addConstantFromGenerator(PropertyGenerator $constant) * * @param non-empty-string $name * @param mixed $value Scalar - * * @return static - *@throws Exception\InvalidArgumentException + * @throws Exception\InvalidArgumentException */ public function addConstant($name, $value, bool $isFinal = false) { @@ -826,7 +825,6 @@ public function addMethods(array $methods) * @param int $flags * @param string $body * @param string $docBlock - * * @return static * @throws Exception\InvalidArgumentException */ diff --git a/src/Generator/FileGenerator.php b/src/Generator/FileGenerator.php index 05b304d3..31a31a83 100644 --- a/src/Generator/FileGenerator.php +++ b/src/Generator/FileGenerator.php @@ -229,7 +229,6 @@ public function getUses($withResolvedAs = false) * non-empty-string|null * }|non-empty-string * > $uses - * * @return FileGenerator */ public function setUses(array $uses) diff --git a/src/Generator/TraitUsageInterface.php b/src/Generator/TraitUsageInterface.php index 010711a8..7bfa8d83 100644 --- a/src/Generator/TraitUsageInterface.php +++ b/src/Generator/TraitUsageInterface.php @@ -11,7 +11,6 @@ interface TraitUsageInterface * * @param non-empty-string $use * @param non-empty-string|null $useAlias - * * @return self */ public function addUse($use, $useAlias = null); @@ -93,7 +92,6 @@ public function removeTrait($traitName); * @param array{traitName: non-empty-string, method: non-empty-string}|non-empty-string $method * @param non-empty-string $alias * @param ReflectionMethod::IS_PUBLIC|ReflectionMethod::IS_PRIVATE|ReflectionMethod::IS_PROTECTED|null $visibility - * * @return $this */ public function addTraitAlias($method, $alias, $visibility = null); diff --git a/src/Generator/ValueGenerator.php b/src/Generator/ValueGenerator.php index c2a7a548..d288caa7 100644 --- a/src/Generator/ValueGenerator.php +++ b/src/Generator/ValueGenerator.php @@ -104,7 +104,7 @@ public function __construct( /** * Init constant list by defined and magic constants - * + * * @deprecated this method attempts to make some magic constants work with the value generator, * but the value generator is not aware of its surrounding, and cannot really * generate constant expressions. For such a functionality, consider using an AST-based @@ -130,13 +130,13 @@ public function initEnvironmentConstants() /** * Add constant to list * - * @param string $constant - * @return $this - * * @deprecated this method attempts to make some magic constants work with the value generator, * but the value generator is not aware of its surrounding, and cannot really * generate constant expressions. For such a functionality, consider using an AST-based * code builder instead. + * + * @param string $constant + * @return $this */ public function addConstant($constant) { @@ -148,13 +148,13 @@ public function addConstant($constant) /** * Delete constant from constant list * - * @param string $constant - * @return bool - * * @deprecated this method attempts to make some magic constants work with the value generator, * but the value generator is not aware of its surrounding, and cannot really * generate constant expressions. For such a functionality, consider using an AST-based * code builder instead. + * + * @param string $constant + * @return bool */ public function deleteConstant($constant) { @@ -168,12 +168,12 @@ public function deleteConstant($constant) /** * Return constant list * - * @return SplArrayObject|StdlibArrayObject - * * @deprecated this method attempts to make some magic constants work with the value generator, * but the value generator is not aware of its surrounding, and cannot really * generate constant expressions. For such a functionality, consider using an AST-based * code builder instead. + * + * @return SplArrayObject|StdlibArrayObject */ public function getConstants() { diff --git a/src/Generic/Prototype/PrototypeClassFactory.php b/src/Generic/Prototype/PrototypeClassFactory.php index eeefcc31..003d6c3c 100644 --- a/src/Generic/Prototype/PrototypeClassFactory.php +++ b/src/Generic/Prototype/PrototypeClassFactory.php @@ -102,7 +102,7 @@ public function getClonedPrototype($prototypeName) if (! $this->hasPrototype($prototypeName)) { $newPrototype = clone $this->genericPrototype; $newPrototype->setName($prototypeName); - + return $newPrototype; } diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index 3756f6d4..42c7b980 100644 --- a/src/Reflection/ClassReflection.php +++ b/src/Reflection/ClassReflection.php @@ -111,7 +111,6 @@ public function getMethod($name) * {@inheritDoc} * * @param int $filter - * * @return list */ #[ReturnTypeWillChange] @@ -176,7 +175,6 @@ public function getProperty($name) * {@inheritDoc} * * @param int $filter - * * @return list */ #[ReturnTypeWillChange] diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index ba4d8030..ba84cc94 100644 --- a/src/Reflection/FunctionReflection.php +++ b/src/Reflection/FunctionReflection.php @@ -199,12 +199,12 @@ public function getParameters() /** * Get return type tag * - * @throws Exception\InvalidArgumentException - * @return DocBlockReflection - * * @deprecated this method is unreliable, and will be dropped in the next major release. * If you are attempting to inspect the return type of an expression, please * use more reliable tools, such as `vimeo/psalm` or `phpstan/phpstan` instead. + * + * @throws Exception\InvalidArgumentException + * @return DocBlockReflection */ public function getReturn() { diff --git a/src/Reflection/MethodReflection.php b/src/Reflection/MethodReflection.php index 821178f1..557e05cd 100644 --- a/src/Reflection/MethodReflection.php +++ b/src/Reflection/MethodReflection.php @@ -7,6 +7,7 @@ use ReturnTypeWillChange; use function array_key_exists; +use function array_map; use function array_shift; use function array_slice; use function class_exists; @@ -176,7 +177,7 @@ public function getPrototype($format = self::PROTOTYPE_AS_ARRAY) public function getParameters() { $method = [$this->getDeclaringClass()->getName(), $this->getName()]; - + return array_map( static fn (PhpReflectionParameter $parameter): ParameterReflection => new ParameterReflection($method, $parameter->getName()), diff --git a/src/Reflection/ParameterReflection.php b/src/Reflection/ParameterReflection.php index 3ab4f5f0..7f4eb874 100644 --- a/src/Reflection/ParameterReflection.php +++ b/src/Reflection/ParameterReflection.php @@ -27,11 +27,11 @@ class ParameterReflection extends ReflectionParameter implements ReflectionInter public function getDeclaringClass() { $reflection = parent::getDeclaringClass(); - + if (! $reflection) { return null; } - + return new ClassReflection($reflection->getName()); } @@ -163,13 +163,13 @@ public function isPrivatePromoted(): bool return (bool) ($property->getModifiers() & ReflectionProperty::IS_PRIVATE); } - + private function promotedProperty(): ?ReflectionProperty { if (! $this->isPromoted()) { return null; } - + $declaringClass = $this->getDeclaringClass(); assert($declaringClass !== null, 'Promoted properties are always part of a class'); From 487c2e2f02f54251dd4fde4c2201f1d3db6a4821 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 01:29:45 +0100 Subject: [PATCH 47/53] Moved complex array shape docblock to the class definition, to avoid PHPCS crashing on it Signed-off-by: Marco Pivetta --- src/Generator/FileGenerator.php | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/Generator/FileGenerator.php b/src/Generator/FileGenerator.php index 31a31a83..f1d55f4f 100644 --- a/src/Generator/FileGenerator.php +++ b/src/Generator/FileGenerator.php @@ -37,6 +37,18 @@ use const T_OPEN_TAG; use const T_WHITESPACE; +/** + * @psalm-type InputUses = array< + * string|int, + * array{ + * 'use': non-empty-string, + * 'as': non-empty-string|null + * }|array{ + * non-empty-string, + * non-empty-string|null + * }|non-empty-string + * > + */ class FileGenerator extends AbstractGenerator { protected string $filename = ''; @@ -219,16 +231,7 @@ public function getUses($withResolvedAs = false) } /** - * @param array< - * string|int, - * array{ - * 'use': non-empty-string, - * 'as': non-empty-string|null - * }|array{ - * non-empty-string, - * non-empty-string|null - * }|non-empty-string - * > $uses + * @param InputUses $uses * @return FileGenerator */ public function setUses(array $uses) From 07b00d166ddb262ced5f7b934ae7c73f35d77f5c Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 16:19:58 +0100 Subject: [PATCH 48/53] Corrected inheritDoc syntax as per code review suggestions Co-authored-by: Gary Lockett Signed-off-by: Marco Pivetta --- src/Generator/ClassGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generator/ClassGenerator.php b/src/Generator/ClassGenerator.php index c428805b..fec3f54e 100644 --- a/src/Generator/ClassGenerator.php +++ b/src/Generator/ClassGenerator.php @@ -727,7 +727,7 @@ public function getProperty($propertyName) return false; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function addUse($use, $useAlias = null) { $this->traitUsageGenerator->addUse($use, $useAlias); From 2e5b31526111762eee56d22f5827c64df7e37d35 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 16:20:11 +0100 Subject: [PATCH 49/53] Corrected inheritDoc syntax as per code review suggestions Co-authored-by: Gary Lockett Signed-off-by: Marco Pivetta --- src/Generator/ClassGenerator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Generator/ClassGenerator.php b/src/Generator/ClassGenerator.php index fec3f54e..8938ee56 100644 --- a/src/Generator/ClassGenerator.php +++ b/src/Generator/ClassGenerator.php @@ -772,7 +772,7 @@ public function removeUseAlias($use) return $this; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getUses() { return $this->traitUsageGenerator->getUses(); From a9d601d091c8478f64275ba15836689200c7e0f0 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 16:34:56 +0100 Subject: [PATCH 50/53] Added a default execution branch that returns `null` in `MethodReflection#isEndingBrace()` Ref: https://github.com/laminas/laminas-code/pull/154#discussion_r1027100746 Signed-off-by: Marco Pivetta --- src/Reflection/MethodReflection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Reflection/MethodReflection.php b/src/Reflection/MethodReflection.php index 557e05cd..45b1e425 100644 --- a/src/Reflection/MethodReflection.php +++ b/src/Reflection/MethodReflection.php @@ -368,7 +368,7 @@ protected function extractPrefixedWhitespace($haystack, $position) * * @param array $haystack * @param int $position - * @return bool|void + * @return bool|null */ protected function isEndingBrace($haystack, $position) { @@ -428,6 +428,8 @@ protected function isEndingBrace($haystack, $position) return false; } } + + return null; } /** From 66064ca32631c3888466fe8f555a71793b0cac52 Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 16:36:19 +0100 Subject: [PATCH 51/53] Applied De Morgan's law to a complex boolean expression to improve readability Ref: https://github.com/laminas/laminas-code/pull/154#discussion_r1027101197 Signed-off-by: Marco Pivetta --- src/Reflection/ParameterReflection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Reflection/ParameterReflection.php b/src/Reflection/ParameterReflection.php index 7f4eb874..78d84d98 100644 --- a/src/Reflection/ParameterReflection.php +++ b/src/Reflection/ParameterReflection.php @@ -45,7 +45,7 @@ public function getClass() { $type = parent::getType(); - if (! ($type instanceof ReflectionNamedType && ! $type->isBuiltin())) { + if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) { return null; } From dd68158de612598d53a7f3dcc96c27c5b3816dbf Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 16:39:50 +0100 Subject: [PATCH 52/53] Replaced `{@inheritDoc}` with `@inheritDoc` where the whole parent docblock is to be imported Ref: https://github.com/laminas/laminas-code/pull/154#discussion_r1027095449 Signed-off-by: Marco Pivetta --- src/Generator/DocBlock/Tag/VarTag.php | 8 ++------ src/Generator/InterfaceGenerator.php | 16 ++++------------ src/Generator/PropertyGenerator.php | 4 +--- src/Generator/TraitUsageGenerator.php | 2 +- src/Reflection/DocBlock/Tag/AuthorTag.php | 2 +- src/Reflection/DocBlock/Tag/GenericTag.php | 2 +- src/Reflection/DocBlock/Tag/LicenseTag.php | 2 +- src/Reflection/DocBlock/Tag/MethodTag.php | 4 ++-- src/Reflection/DocBlock/Tag/ParamTag.php | 4 ++-- src/Reflection/DocBlock/Tag/PropertyTag.php | 4 ++-- src/Reflection/DocBlock/Tag/ReturnTag.php | 4 ++-- src/Reflection/DocBlock/Tag/ThrowsTag.php | 4 ++-- src/Reflection/DocBlock/Tag/VarTag.php | 10 +++------- 13 files changed, 24 insertions(+), 42 deletions(-) diff --git a/src/Generator/DocBlock/Tag/VarTag.php b/src/Generator/DocBlock/Tag/VarTag.php index e67919bd..15d11ad8 100644 --- a/src/Generator/DocBlock/Tag/VarTag.php +++ b/src/Generator/DocBlock/Tag/VarTag.php @@ -20,9 +20,7 @@ public function __construct(?string $variableName = null, $types = [], ?string $ parent::__construct($types, $description); } - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function getName(): string { return 'var'; @@ -46,9 +44,7 @@ public function getVariableName(): ?string return $this->variableName; } - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function generate(): string { return '@var' diff --git a/src/Generator/InterfaceGenerator.php b/src/Generator/InterfaceGenerator.php index 56011aac..867fb4bc 100644 --- a/src/Generator/InterfaceGenerator.php +++ b/src/Generator/InterfaceGenerator.php @@ -116,17 +116,13 @@ public static function fromArray(array $array) return $cg; } - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function addPropertyFromGenerator(PropertyGenerator $property) { return $this; } - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function addMethodFromGenerator(MethodGenerator $method) { $method->setInterface(true); @@ -134,17 +130,13 @@ public function addMethodFromGenerator(MethodGenerator $method) return parent::addMethodFromGenerator($method); } - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function setExtendedClass($extendedClass) { return $this; } - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function setAbstract($isAbstract) { return $this; diff --git a/src/Generator/PropertyGenerator.php b/src/Generator/PropertyGenerator.php index 19299481..833345eb 100644 --- a/src/Generator/PropertyGenerator.php +++ b/src/Generator/PropertyGenerator.php @@ -230,9 +230,7 @@ public function isReadonly(): bool return (bool) ($this->flags & self::FLAG_READONLY); } - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function setFlags($flags) { $flags = array_reduce((array) $flags, static function (int $a, int $b): int { diff --git a/src/Generator/TraitUsageGenerator.php b/src/Generator/TraitUsageGenerator.php index de375e7a..861762e7 100644 --- a/src/Generator/TraitUsageGenerator.php +++ b/src/Generator/TraitUsageGenerator.php @@ -62,7 +62,7 @@ public function addUse($use, $useAlias = null) return $this; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getUses() { return array_values($this->uses); diff --git a/src/Reflection/DocBlock/Tag/AuthorTag.php b/src/Reflection/DocBlock/Tag/AuthorTag.php index f897dea1..02c7a7ef 100644 --- a/src/Reflection/DocBlock/Tag/AuthorTag.php +++ b/src/Reflection/DocBlock/Tag/AuthorTag.php @@ -19,7 +19,7 @@ public function getName() return 'author'; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function initialize($content) { $match = []; diff --git a/src/Reflection/DocBlock/Tag/GenericTag.php b/src/Reflection/DocBlock/Tag/GenericTag.php index 8acc0e49..8bc364b7 100644 --- a/src/Reflection/DocBlock/Tag/GenericTag.php +++ b/src/Reflection/DocBlock/Tag/GenericTag.php @@ -29,7 +29,7 @@ public function __construct($contentSplitCharacter = ' ') $this->contentSplitCharacter = $contentSplitCharacter; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function initialize($content) { $this->parse($content); diff --git a/src/Reflection/DocBlock/Tag/LicenseTag.php b/src/Reflection/DocBlock/Tag/LicenseTag.php index f9d48821..d580c734 100644 --- a/src/Reflection/DocBlock/Tag/LicenseTag.php +++ b/src/Reflection/DocBlock/Tag/LicenseTag.php @@ -19,7 +19,7 @@ public function getName() return 'license'; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function initialize($content) { $match = []; diff --git a/src/Reflection/DocBlock/Tag/MethodTag.php b/src/Reflection/DocBlock/Tag/MethodTag.php index b4a4fb97..edb1dee2 100644 --- a/src/Reflection/DocBlock/Tag/MethodTag.php +++ b/src/Reflection/DocBlock/Tag/MethodTag.php @@ -26,7 +26,7 @@ public function getName() return 'method'; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function initialize($content) { $match = []; @@ -66,7 +66,7 @@ public function getReturnType() return $this->types[0]; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes() { return $this->types; diff --git a/src/Reflection/DocBlock/Tag/ParamTag.php b/src/Reflection/DocBlock/Tag/ParamTag.php index 708d7d76..963542ac 100644 --- a/src/Reflection/DocBlock/Tag/ParamTag.php +++ b/src/Reflection/DocBlock/Tag/ParamTag.php @@ -24,7 +24,7 @@ public function getName() return 'param'; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function initialize($content) { $matches = []; @@ -60,7 +60,7 @@ public function getType() return $this->types[0]; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes() { return $this->types; diff --git a/src/Reflection/DocBlock/Tag/PropertyTag.php b/src/Reflection/DocBlock/Tag/PropertyTag.php index 9e95a3fe..1bfdcdb7 100644 --- a/src/Reflection/DocBlock/Tag/PropertyTag.php +++ b/src/Reflection/DocBlock/Tag/PropertyTag.php @@ -25,7 +25,7 @@ public function getName() return 'property'; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function initialize($content) { $match = []; @@ -60,7 +60,7 @@ public function getType() return $this->types[0]; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes() { return $this->types; diff --git a/src/Reflection/DocBlock/Tag/ReturnTag.php b/src/Reflection/DocBlock/Tag/ReturnTag.php index 2aa1c31d..f951743b 100644 --- a/src/Reflection/DocBlock/Tag/ReturnTag.php +++ b/src/Reflection/DocBlock/Tag/ReturnTag.php @@ -23,7 +23,7 @@ public function getName() return 'return'; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function initialize($content) { $matches = []; @@ -52,7 +52,7 @@ public function getType() return $this->types[0]; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes() { return $this->types; diff --git a/src/Reflection/DocBlock/Tag/ThrowsTag.php b/src/Reflection/DocBlock/Tag/ThrowsTag.php index a7243bd9..30f2fa90 100644 --- a/src/Reflection/DocBlock/Tag/ThrowsTag.php +++ b/src/Reflection/DocBlock/Tag/ThrowsTag.php @@ -25,7 +25,7 @@ public function getName() return 'throws'; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function initialize($content) { $matches = []; @@ -50,7 +50,7 @@ public function getType() return implode('|', $this->getTypes()); } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes() { return $this->types; diff --git a/src/Reflection/DocBlock/Tag/VarTag.php b/src/Reflection/DocBlock/Tag/VarTag.php index 5dfbd6a3..5100f620 100644 --- a/src/Reflection/DocBlock/Tag/VarTag.php +++ b/src/Reflection/DocBlock/Tag/VarTag.php @@ -22,17 +22,13 @@ class VarTag implements TagInterface, PhpDocTypedTagInterface /** @var string|null */ private $description; - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function getName(): string { return 'var'; } - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function initialize($content): void { $match = []; @@ -60,7 +56,7 @@ public function initialize($content): void } } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes(): array { return $this->types; From 63739216703f88ba8fbbe7fec6d8656babf1fbdd Mon Sep 17 00:00:00 2001 From: Marco Pivetta Date: Sat, 19 Nov 2022 16:43:03 +0100 Subject: [PATCH 53/53] Simplified `EnumGenerator` to have more explicit codegen logic around `BackedCases` Ref: https://github.com/laminas/laminas-code/pull/154#discussion_r1027092733 Signed-off-by: Marco Pivetta --- src/Generator/EnumGenerator/EnumGenerator.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Generator/EnumGenerator/EnumGenerator.php b/src/Generator/EnumGenerator/EnumGenerator.php index dbd9f8b1..38344d89 100644 --- a/src/Generator/EnumGenerator/EnumGenerator.php +++ b/src/Generator/EnumGenerator/EnumGenerator.php @@ -54,11 +54,11 @@ public function generate(): string private function retrieveType(): string { - if ($this->cases instanceof PureCases) { - return ''; + if ($this->cases instanceof BackedCases) { + return ': ' . $this->cases->type; } - return ': ' . $this->cases->type; + return ''; } private function retrieveCases(): string