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/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 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 }} diff --git a/composer.json b/composer.json index 5bc1efeb..94671dba 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.1.0" }, "require-dev": { "ext-phar": "*", @@ -29,17 +29,14 @@ "dealerdirect/phpcodesniffer-composer-installer": true }, "platform": { - "php": "7.4.99" + "php": "8.1.99" }, "sort-packages": true }, "autoload": { "psr-4": { "Laminas\\Code\\": "src/" - }, - "files": [ - "polyfill/ReflectionEnumPolyfill.php" - ] + } }, "autoload-dev": { "psr-4": { diff --git a/composer.lock b/composer.lock index 697dfc2f..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": "bdac2a2a26a0a63994c2cbae675d445b", + "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": ">=7.4, <8.2" + "php": "~8.1.0" }, "platform-dev": { "ext-phar": "*" }, "platform-overrides": { - "php": "7.4.99" + "php": "8.1.99" }, "plugin-api-version": "2.3.0" } 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/psalm-baseline.xml b/psalm-baseline.xml index bca02bc8..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,35 +70,25 @@ $name - - $use + $value - - $use + static::IMPLEMENTS_KEYWORD static::OBJECT_TYPE $this->traitUsageGenerator->getUseAlias($fqnClassName) - - $classReflection->getDocBlock() + strrpos($name, '\\') strrpos($name, '\\') - - getInterfaces - getName - $namespaceAlias - - method_exists($constReflection, 'isFinal') - is_array($constant) @@ -116,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 - @@ -149,16 +112,15 @@ AuthorTag - - $authorEmail - $authorName - - - $content - $name - + + $this + string|null + + + $this->name + @@ -167,19 +129,8 @@ ReturnTag - - $licenseName - $url - - - $types - - - $methodName - MethodTag - (bool) $isStatic @@ -196,18 +147,8 @@ ParamTag ParamTag - + $variableName - ParamTag - - - - - $types - - - $propertyName - PropertyTag @@ -219,19 +160,6 @@ ReturnTag ReturnTag - - ReturnTag - - - - - ThrowsTag - - - - - VarTag - @@ -260,43 +188,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 - - - 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 + @@ -307,15 +218,16 @@ $docBlock - + $uses - + + + array<int, array{string, null|string, false|null|string}> + $value - - $alias - $import + $value $value $value @@ -326,41 +238,39 @@ $name $name - - $alias - $import - $import - $use + $value - - array<int, array{string, null|string, false|null|string}> - + + 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 @@ -369,9 +279,6 @@ $value $value - - $classReflection->getDocBlock() - new static($array['name']) new static($classReflection->getName()) @@ -382,10 +289,8 @@ DocBlockGenerator::fromArray($value) ParameterGenerator::fromArray($parameter) - + $array['name'] - $parameterOutput - $reflectionMethod->isStatic() $value $value $value @@ -400,18 +305,12 @@ $name - - $parameterOutput[] - $value $reflectionMethod->getDocBlock() - - $parameterOutput - (bool) $returnsReference @@ -421,14 +320,8 @@ - - string - - + $array['name'] - $defaultValue - $reflectionParameter->getDefaultValue() - $value $value $value $value @@ -443,7 +336,6 @@ $value - (bool) $passedByReference (bool) $variadic @@ -475,12 +367,6 @@ $defaultValue - - $reflectionProperty->getDocBlock() - - - method_exists($reflectionProperty, 'isReadonly') - new static($array['name']) new static() @@ -513,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 @@ -608,14 +459,10 @@ $method - - - addTraitAlias - addTraitOverride - removeTrait - - + + static fn(ReflectionNamedType $type): string => self::reflectionNamedTypeToString($type, $currentClass) + allowsNull getName @@ -623,9 +470,11 @@ getParentClass getTypes - + + getConstants + $constants instanceof StdlibArrayObject @@ -656,17 +505,9 @@ - - addPrototype - setGenericPrototype - - - $newPrototype + $newPrototype - - clone $this->prototypes[$prototypeName] - PrototypeInterface @@ -679,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 + @@ -876,9 +604,9 @@ - - ParameterReflection[] - + + detectType + $returnTypes $returnTypes @@ -919,12 +647,9 @@ - - bool - - - ParameterReflection[] - + + detectType + $haystack[$i][0] $haystack[$i][0] @@ -961,36 +686,33 @@ - $phpReflection->getName() + $function->getName() - - #[ReturnTypeWillChange] - #[ReturnTypeWillChange] - #[ReturnTypeWillChange] - ReflectionParameter - public function __toString() - - - $phpReflectionType->getName() - + + getDeclaringClass + getDocBlock + getModifiers + getModifiers + getModifiers + getName + getName + getName + getName + getName + getName + getProperty + getTags + string|null - - getName - $type->getName() - - getName - - - $type - - + getName getName + isBuiltin @@ -1137,6 +859,11 @@ testSetFlagsWithArray + + + 'bool' + + '' @@ -1148,20 +875,19 @@ ['Class1', 'Class2'] - - $resource + + '' + 'public' + 'public' ExceptionInterface::class [] new ClassGenerator() - new stdClass() [] new ClassGenerator() - - 'public' - 'public' + true true true @@ -1178,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] @@ -1403,6 +1125,9 @@ + + $file->getUses() + testClassNotFoundException testConstruction @@ -1531,11 +1256,11 @@ testTypeHintWithValidClassName testTypehintsWithNamespaceInNamepsacedClassReturnTypewithBackslash - - $parameter[3] - + + $type + new stdClass() @@ -1626,11 +1351,6 @@ type - - - setName - - someFunction @@ -1660,11 +1380,6 @@ bool - - - TypeableTag - - 'LaminasTest_Code_NsTest_BarClass' @@ -1687,6 +1402,13 @@ + + getConstants + getConstants + initEnvironmentConstants + initEnvironmentConstants + initEnvironmentConstants + $constants @@ -1742,12 +1464,15 @@ testPropertyReturns testStartLine - + $parent - - + + getName - + + + $traitsArray[TestTraitClass3::class] + @@ -1871,6 +1596,10 @@ __NAMESPACE__ . '\\' . $functionName + + getPrototype + getPrototype + 'LaminasTest\Code\Reflection\TestAsset\function1' 'LaminasTest\Code\Reflection\TestAsset\function1' @@ -1984,6 +1713,16 @@ 'ReflectionException' __NAMESPACE__ . '\\' . $className + + getPrototype + getPrototype + getPrototype + getPrototype + getPrototype + getPrototype + getPrototype + getPrototype + testCanParseClassBodyWhenUsingTrait testCodeGetBodyReturnsEmptyWithCommentedFunction @@ -2003,6 +1742,13 @@ + + detectType + detectType + detectType + detectType + detectType + testCallableTypeHint testClassReturn @@ -2552,19 +2298,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/Generator/AbstractGenerator.php b/src/Generator/AbstractGenerator.php index c1baaf7e..bce234e1 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 get_debug_type; use function is_array; -use function is_object; 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 5ebfda11..8938ee56 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; @@ -80,8 +80,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)); } $cg->setAbstract($classReflection->isAbstract()); @@ -120,13 +122,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); @@ -582,10 +584,10 @@ public function addConstantFromGenerator(PropertyGenerator $constant) /** * Add Constant * - * @param string $name Non-empty string - * @param string|int|null|float|array $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 +727,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 +772,7 @@ public function removeUseAlias($use) return $this; } - /** - * Returns the "use" classes - * - * @return array - */ + /** @inheritDoc */ public function getUses() { return $this->traitUsageGenerator->getUses(); @@ -828,13 +820,13 @@ 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 +1036,6 @@ public function generate() } } - $indent = $this->getIndentation(); $output = ''; if (null !== ($namespace = $this->getNamespaceName())) { @@ -1081,7 +1072,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,33 +1115,27 @@ 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; } throw new Exception\InvalidArgumentException(sprintf( 'Expected value for constant, value must be a "scalar" or "null", "%s" found', - gettype($value) + get_debug_type($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/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() { 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() { 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' 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/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' 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' 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() { 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/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 0e1d5550..b82ead32 100644 --- a/src/Generator/EnumGenerator/Cases/CaseFactory.php +++ b/src/Generator/EnumGenerator/Cases/CaseFactory.php @@ -2,17 +2,16 @@ 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; -use const PHP_VERSION_ID; - /** @internal */ final class CaseFactory { @@ -47,24 +46,30 @@ 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) { - $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 23d5e0a0..38344d89 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 { @@ -57,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->getBackedType(); + return ''; } private function retrieveCases(): string @@ -70,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 ) ); } @@ -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/FileGenerator.php b/src/Generator/FileGenerator.php index a541f8fb..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 = ''; @@ -48,7 +60,7 @@ class FileGenerator extends AbstractGenerator protected string $namespace = ''; - /** @psalm-var list */ + /** @psalm-var list */ protected array $uses = []; /** @@ -219,7 +231,7 @@ public function getUses($withResolvedAs = false) } /** - * @param array $uses + * @param InputUses $uses * @return FileGenerator */ public function setUses(array $uses) @@ -227,22 +239,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 +515,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 diff --git a/src/Generator/InterfaceGenerator.php b/src/Generator/InterfaceGenerator.php index 183c1af1..867fb4bc 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 @@ -114,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); @@ -132,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/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 .= ')'; 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; } diff --git a/src/Generator/PropertyGenerator.php b/src/Generator/PropertyGenerator.php index 7e25a0cc..833345eb 100644 --- a/src/Generator/PropertyGenerator.php +++ b/src/Generator/PropertyGenerator.php @@ -5,11 +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 method_exists; use function sprintf; use function str_replace; use function strtolower; @@ -67,15 +64,17 @@ 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()) { $property->setStatic(true); } - if (method_exists($reflectionProperty, 'isReadonly') && $reflectionProperty->isReadonly()) { + if ($reflectionProperty->isReadonly()) { $property->setReadonly(true); } @@ -164,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) )); } @@ -179,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); @@ -233,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 { @@ -262,9 +257,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( diff --git a/src/Generator/TraitUsageGenerator.php b/src/Generator/TraitUsageGenerator.php index d2d50b5b..861762e7 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 943255b5..7bfa8d83 100644 --- a/src/Generator/TraitUsageInterface.php +++ b/src/Generator/TraitUsageInterface.php @@ -2,13 +2,15 @@ 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 +18,7 @@ public function addUse($use, $useAlias = null); /** * Returns the "use" classes * - * @return array + * @return list */ public function getUses(); @@ -70,6 +72,7 @@ public function getTraits(); * Remove a trait by its name * * @param string $traitName + * @return self */ public function removeTrait($traitName); @@ -86,17 +89,21 @@ 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 mixed $method String or Array - * @param string $alias - * @param null|int $visibility + * @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); /** - * @return array + * @return array< + * non-empty-string, + * array{ + * alias: string, + * visibility: ReflectionMethod::IS_PRIVATE|ReflectionMethod::IS_PROTECTED|ReflectionMethod::IS_PUBLIC|null + * } + * > */ public function getTraitAliases(); @@ -120,6 +127,7 @@ public function getTraitAliases(); * @param mixed $method * @param mixed $traitsToReplace + * @return $this */ public function addTraitOverride($method, $traitsToReplace); diff --git a/src/Generator/ValueGenerator.php b/src/Generator/ValueGenerator.php index 56251d11..d288caa7 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; @@ -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( @@ -103,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() { @@ -124,6 +130,11 @@ public function initEnvironmentConstants() /** * Add constant to list * + * @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 */ @@ -137,6 +148,11 @@ public function addConstant($constant) /** * Delete constant from constant list * + * @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 */ @@ -152,6 +168,11 @@ public function deleteConstant($constant) /** * Return constant list * + * @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() @@ -422,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) )); } @@ -449,8 +470,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 +480,7 @@ public function setOutputMode($outputMode) } /** - * @return string + * @return self::OUTPUT_* */ public function getOutputMode() { diff --git a/src/Generic/Prototype/PrototypeClassFactory.php b/src/Generic/Prototype/PrototypeClassFactory.php index 1bc85751..003d6c3c 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); } diff --git a/src/Reflection/ClassReflection.php b/src/Reflection/ClassReflection.php index a6499afb..42c7b980 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,55 @@ 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 +172,21 @@ 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/src/Reflection/DocBlock/Tag/AuthorTag.php b/src/Reflection/DocBlock/Tag/AuthorTag.php index 9e5c1b47..02c7a7ef 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"; diff --git a/src/Reflection/DocBlock/Tag/GenericTag.php b/src/Reflection/DocBlock/Tag/GenericTag.php index d79d9f4e..8bc364b7 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) { diff --git a/src/Reflection/DocBlock/Tag/LicenseTag.php b/src/Reflection/DocBlock/Tag/LicenseTag.php index d06ec44d..d580c734 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/MethodTag.php b/src/Reflection/DocBlock/Tag/MethodTag.php index c14c60b8..edb1dee2 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,46 +60,37 @@ public function initialize($tagDocblockLine) public function getReturnType() { if (empty($this->types)) { - return; + return null; } return $this->types[0]; } - /** {@inheritDoc} */ + /** @inheritDoc */ 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"; diff --git a/src/Reflection/DocBlock/Tag/ParamTag.php b/src/Reflection/DocBlock/Tag/ParamTag.php index 5fc20127..963542ac 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; } @@ -69,25 +60,19 @@ public function getType() return $this->types[0]; } - /** {@inheritDoc} */ + /** @inheritDoc */ 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; 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(); } diff --git a/src/Reflection/DocBlock/Tag/PropertyTag.php b/src/Reflection/DocBlock/Tag/PropertyTag.php index 24e0295b..1bfdcdb7 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,13 +54,13 @@ public function initialize($tagDocblockLine) public function getType() { if (empty($this->types)) { - return; + return null; } 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 d74d705e..f951743b 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; } @@ -55,14 +52,14 @@ public function getType() return $this->types[0]; } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes() { return $this->types; } /** - * @return string + * @return string|null */ public function getDescription() { diff --git a/src/Reflection/DocBlock/Tag/ThrowsTag.php b/src/Reflection/DocBlock/Tag/ThrowsTag.php index d382ade8..30f2fa90 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; /** @@ -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]); @@ -53,14 +50,14 @@ public function getType() return implode('|', $this->getTypes()); } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes() { return $this->types; } /** - * @return string + * @return string|null */ public function getDescription() { diff --git a/src/Reflection/DocBlock/Tag/VarTag.php b/src/Reflection/DocBlock/Tag/VarTag.php index e58ffdf3..5100f620 100644 --- a/src/Reflection/DocBlock/Tag/VarTag.php +++ b/src/Reflection/DocBlock/Tag/VarTag.php @@ -22,25 +22,21 @@ class VarTag implements TagInterface, PhpDocTypedTagInterface /** @var string|null */ private $description; - /** - * {@inheritDoc} - */ + /** @inheritDoc */ public function getName(): string { return 'var'; } - /** - * {@inheritDoc} - */ - public function initialize($tagDocblockLine): void + /** @inheritDoc */ + public function initialize($content): void { $match = []; if ( ! preg_match( '#^([^\$]\S+)?\s*(\$[\S]+)?\s*(.*)$#m', - $tagDocblockLine, + $content, $match ) ) { @@ -60,7 +56,7 @@ public function initialize($tagDocblockLine): void } } - /** {@inheritDoc} */ + /** @inheritDoc */ public function getTypes(): array { return $this->types; diff --git a/src/Reflection/FunctionReflection.php b/src/Reflection/FunctionReflection.php index 4c547db1..ba84cc94 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; @@ -126,6 +127,10 @@ public function getContents($includeDocBlock = true) /** * Get method prototype * + * @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 */ @@ -177,26 +182,27 @@ 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() + ); } /** * Get return type tag * + * @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 */ diff --git a/src/Reflection/MethodReflection.php b/src/Reflection/MethodReflection.php index b026b703..45b1e425 100644 --- a/src/Reflection/MethodReflection.php +++ b/src/Reflection/MethodReflection.php @@ -3,9 +3,11 @@ namespace Laminas\Code\Reflection; use ReflectionMethod as PhpReflectionMethod; +use ReflectionParameter as PhpReflectionParameter; use ReturnTypeWillChange; use function array_key_exists; +use function array_map; use function array_shift; use function array_slice; use function class_exists; @@ -85,6 +87,10 @@ public function getDeclaringClass() /** * Get method prototype * + * @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 */ @@ -165,24 +171,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); + $method = [$this->getDeclaringClass()->getName(), $this->getName()]; - return $laminasReflections; + return array_map( + static fn (PhpReflectionParameter $parameter): ParameterReflection + => new ParameterReflection($method, $parameter->getName()), + parent::getParameters() + ); } /** @@ -368,7 +368,7 @@ protected function extractPrefixedWhitespace($haystack, $position) * * @param array $haystack * @param int $position - * @return bool + * @return bool|null */ protected function isEndingBrace($haystack, $position) { @@ -428,6 +428,8 @@ protected function isEndingBrace($haystack, $position) return false; } } + + return null; } /** diff --git a/src/Reflection/ParameterReflection.php b/src/Reflection/ParameterReflection.php index 5e11ec3a..78d84d98 100644 --- a/src/Reflection/ParameterReflection.php +++ b/src/Reflection/ParameterReflection.php @@ -5,12 +5,14 @@ use Laminas\Code\Reflection\DocBlock\Tag\ParamTag; use ReflectionClass; use ReflectionMethod; +use ReflectionNamedType; use ReflectionParameter; use ReflectionProperty; use ReturnTypeWillChange; -use function method_exists; +use function assert; +/** @psalm-immutable */ class ParameterReflection extends ReflectionParameter implements ReflectionInterface { /** @var bool */ @@ -19,16 +21,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); + $reflection = parent::getDeclaringClass(); - return $laminasReflection; + if (! $reflection) { + return null; + } + + return new ClassReflection($reflection->getName()); } /** @@ -39,15 +43,13 @@ public function getDeclaringClass() #[ReturnTypeWillChange] public function getClass() { - $phpReflectionType = parent::getType(); - if ($phpReflectionType === null) { + $type = parent::getType(); + + if (! $type instanceof ReflectionNamedType || $type->isBuiltin()) { return null; } - $laminasReflection = new ClassReflection($phpReflectionType->getName()); - unset($phpReflectionType); - - return $laminasReflection; + return new ClassReflection($type->getName()); } /** @@ -58,34 +60,39 @@ 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()); } /** * Get parameter type * + * @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() { 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) { @@ -124,48 +131,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 - { - if (! method_exists(parent::class, 'isPromoted')) { + if ($property === null) { return false; } - return (bool) parent::isPromoted(); + return (bool) ($property->getModifiers() & ReflectionProperty::IS_PUBLIC); } - public function isPublicPromoted(): bool + public function isProtectedPromoted(): bool { - return $this->isPromoted() - && $this->getDeclaringClass() - ->getProperty($this->getName()) - ->getModifiers() - & ReflectionProperty::IS_PUBLIC; + $property = $this->promotedProperty(); + + if ($property === null) { + return false; + } + + return (bool) ($property->getModifiers() & ReflectionProperty::IS_PROTECTED); } - public function isProtectedPromoted(): bool + public function isPrivatePromoted(): 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_PRIVATE); } - public function isPrivatePromoted(): bool + private function promotedProperty(): ?ReflectionProperty { - return $this->isPromoted() - && $this->getDeclaringClass() - ->getProperty($this->getName()) - ->getModifiers() - & ReflectionProperty::IS_PRIVATE; + if (! $this->isPromoted()) { + return null; + } + + $declaringClass = $this->getDeclaringClass(); + + assert($declaringClass !== null, 'Promoted properties are always part of a class'); + + return $declaringClass->getProperty($this->getName()); } } 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 ); } 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)']; } /** 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); } }