diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1de81ec..cdf81c1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,19 +1,28 @@
name: CI
-on: [push, pull_request]
+on:
+ push:
+ pull_request:
+
+permissions:
+ contents: read
+ actions: read
jobs:
composer:
+ permissions:
+ contents: read
+ actions: write
runs-on: ubuntu-latest
strategy:
matrix:
- php: [ 8.3, 8.4 ]
+ php: [ 8.3, 8.4, 8.5 ]
steps:
- - uses: actions/checkout@v4
+ - uses: actions/checkout@v6
- name: Cache Composer dependencies
- uses: actions/cache@v4
+ uses: actions/cache@v5
with:
path: /tmp/composer-cache
key: ${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
@@ -22,9 +31,10 @@ jobs:
uses: php-actions/composer@v6
with:
php_version: ${{ matrix.php }}
+ php_extensions: pcntl
- name: Archive build
- run: mkdir /tmp/github-actions/ && tar -cvf /tmp/github-actions/build.tar ./
+ run: mkdir /tmp/github-actions/ && tar --exclude=".git" -cvf /tmp/github-actions/build.tar ./
- name: Upload build archive for test runners
uses: actions/upload-artifact@v4
@@ -37,7 +47,7 @@ jobs:
needs: [ composer ]
strategy:
matrix:
- php: [ 8.3, 8.4 ]
+ php: [ 8.3, 8.4, 8.5 ]
outputs:
coverage: ${{ steps.store-coverage.outputs.coverage_text }}
@@ -60,12 +70,11 @@ jobs:
php_extensions: xdebug
coverage_text: _coverage/coverage.txt
coverage_clover: _coverage/clover.xml
- bootstrap: vendor/autoload.php
- name: Store coverage data
uses: actions/upload-artifact@v4
with:
- name: code-coverage-${{ matrix.php }}
+ name: code-coverage-${{ matrix.php }}-${{ github.run_number }}
path: _coverage
coverage:
@@ -73,28 +82,30 @@ jobs:
needs: [ phpunit ]
strategy:
matrix:
- php: [ 8.3, 8.4 ]
+ php: [ 8.3, 8.4, 8.5 ]
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
- name: code-coverage-${{ matrix.php }}
+ name: code-coverage-${{ matrix.php }}-${{ github.run_number }}
path: _coverage
- name: Output coverage
run: cat "_coverage/coverage.txt"
- name: Upload to Codecov
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v5
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
phpstan:
runs-on: ubuntu-latest
needs: [ composer ]
strategy:
matrix:
- php: [ 8.3, 8.4 ]
+ php: [ 8.3, 8.4, 8.5 ]
steps:
- uses: actions/download-artifact@v4
@@ -110,6 +121,55 @@ jobs:
with:
php_version: ${{ matrix.php }}
path: src/
+ level: 6
+ memory_limit: 256M
+
+ phpmd:
+ runs-on: ubuntu-latest
+ needs: [ composer ]
+ strategy:
+ matrix:
+ php: [ 8.3, 8.4, 8.5 ]
+
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ name: build-artifact-${{ matrix.php }}
+ path: /tmp/github-actions
+
+ - name: Extract build archive
+ run: tar -xvf /tmp/github-actions/build.tar ./
+
+ - name: PHP Mess Detector
+ uses: php-actions/phpmd@v1
+ with:
+ php_version: ${{ matrix.php }}
+ path: src/
+ output: text
+ ruleset: phpmd.xml
+
+ phpcs:
+ runs-on: ubuntu-latest
+ needs: [ composer ]
+ strategy:
+ matrix:
+ php: [ 8.3, 8.4, 8.5 ]
+
+ steps:
+ - uses: actions/download-artifact@v4
+ with:
+ name: build-artifact-${{ matrix.php }}
+ path: /tmp/github-actions
+
+ - name: Extract build archive
+ run: tar -xvf /tmp/github-actions/build.tar ./
+
+ - name: PHP Code Sniffer
+ uses: php-actions/phpcs@v1
+ with:
+ php_version: ${{ matrix.php }}
+ path: src/
+ standard: phpcs.xml
remove_old_artifacts:
runs-on: ubuntu-latest
diff --git a/composer.json b/composer.json
index b2ce862..fbdbba7 100644
--- a/composer.json
+++ b/composer.json
@@ -4,13 +4,15 @@
"type": "library",
"require": {
- "php": ">=8.2",
+ "php": ">=8.3",
"phpgt/typesafegetter": "^v1.2",
"magicalex/write-ini-file": "v1.2.4"
},
"require-dev": {
"phpstan/phpstan": "^2.1",
- "phpunit/phpunit": "^12.4"
+ "phpunit/phpunit": "^12.4",
+ "squizlabs/php_codesniffer": "^4.0",
+ "phpmd/phpmd": "^2.15"
},
"license": "MIT",
diff --git a/composer.lock b/composer.lock
index 788ca66..efe49a4 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": "0908843383dc49b1fd799830ac81f6af",
+ "content-hash": "61ba22e1b2bff7d54287b5c50540418c",
"packages": [
{
"name": "magicalex/write-ini-file",
@@ -59,16 +59,16 @@
},
{
"name": "phpgt/typesafegetter",
- "version": "v1.3.2",
+ "version": "v1.3.3",
"source": {
"type": "git",
- "url": "https://github.com/PhpGt/TypeSafeGetter.git",
- "reference": "f760c05a37b1cc188dcbf800c5fdfab8a926b4b0"
+ "url": "https://github.com/phpgt/TypeSafeGetter.git",
+ "reference": "a0d339103828791989cbb81f760d252f3c2f8b8c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PhpGt/TypeSafeGetter/zipball/f760c05a37b1cc188dcbf800c5fdfab8a926b4b0",
- "reference": "f760c05a37b1cc188dcbf800c5fdfab8a926b4b0",
+ "url": "https://api.github.com/repos/phpgt/TypeSafeGetter/zipball/a0d339103828791989cbb81f760d252f3c2f8b8c",
+ "reference": "a0d339103828791989cbb81f760d252f3c2f8b8c",
"shasum": ""
},
"require": {
@@ -98,8 +98,8 @@
],
"description": "An interface for objects that expose type-safe getter methods.",
"support": {
- "issues": "https://github.com/PhpGt/TypeSafeGetter/issues",
- "source": "https://github.com/PhpGt/TypeSafeGetter/tree/v1.3.2"
+ "issues": "https://github.com/phpgt/TypeSafeGetter/issues",
+ "source": "https://github.com/phpgt/TypeSafeGetter/tree/v1.3.3"
},
"funding": [
{
@@ -107,10 +107,155 @@
"type": "github"
}
],
- "time": "2023-04-28T14:42:27+00:00"
+ "time": "2026-03-10T22:28:01+00:00"
}
],
"packages-dev": [
+ {
+ "name": "composer/pcre",
+ "version": "3.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/pcre.git",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.4 || ^8.0"
+ },
+ "conflict": {
+ "phpstan/phpstan": "<1.11.10"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.12 || ^2",
+ "phpstan/phpstan-strict-rules": "^1 || ^2",
+ "phpunit/phpunit": "^8 || ^9"
+ },
+ "type": "library",
+ "extra": {
+ "phpstan": {
+ "includes": [
+ "extension.neon"
+ ]
+ },
+ "branch-alias": {
+ "dev-main": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Composer\\Pcre\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Jordi Boggiano",
+ "email": "j.boggiano@seld.be",
+ "homepage": "http://seld.be"
+ }
+ ],
+ "description": "PCRE wrapping library that offers type-safe preg_* replacements.",
+ "keywords": [
+ "PCRE",
+ "preg",
+ "regex",
+ "regular expression"
+ ],
+ "support": {
+ "issues": "https://github.com/composer/pcre/issues",
+ "source": "https://github.com/composer/pcre/tree/3.3.2"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-11-12T16:29:46+00:00"
+ },
+ {
+ "name": "composer/xdebug-handler",
+ "version": "3.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/composer/xdebug-handler.git",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef",
+ "shasum": ""
+ },
+ "require": {
+ "composer/pcre": "^1 || ^2 || ^3",
+ "php": "^7.2.5 || ^8.0",
+ "psr/log": "^1 || ^2 || ^3"
+ },
+ "require-dev": {
+ "phpstan/phpstan": "^1.0",
+ "phpstan/phpstan-strict-rules": "^1.1",
+ "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Composer\\XdebugHandler\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "John Stevenson",
+ "email": "john-stevenson@blueyonder.co.uk"
+ }
+ ],
+ "description": "Restarts a process without Xdebug.",
+ "keywords": [
+ "Xdebug",
+ "performance"
+ ],
+ "support": {
+ "irc": "ircs://irc.libera.chat:6697/composer",
+ "issues": "https://github.com/composer/xdebug-handler/issues",
+ "source": "https://github.com/composer/xdebug-handler/tree/3.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://packagist.com",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/composer",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/composer/composer",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-05-06T16:37:16+00:00"
+ },
{
"name": "myclabs/deep-copy",
"version": "1.13.4",
@@ -173,16 +318,16 @@
},
{
"name": "nikic/php-parser",
- "version": "v5.6.1",
+ "version": "v5.7.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2"
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
- "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
@@ -225,9 +370,72 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
+ },
+ "time": "2025-12-06T11:56:16+00:00"
+ },
+ {
+ "name": "pdepend/pdepend",
+ "version": "2.16.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/pdepend/pdepend.git",
+ "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58"
},
- "time": "2025-08-13T20:13:15+00:00"
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/pdepend/pdepend/zipball/f942b208dc2a0868454d01b29f0c75bbcfc6ed58",
+ "reference": "f942b208dc2a0868454d01b29f0c75bbcfc6ed58",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.7",
+ "symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0",
+ "symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0",
+ "symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0",
+ "symfony/polyfill-mbstring": "^1.19"
+ },
+ "require-dev": {
+ "easy-doc/easy-doc": "0.0.0|^1.2.3",
+ "gregwar/rst": "^1.0",
+ "squizlabs/php_codesniffer": "^2.0.0"
+ },
+ "bin": [
+ "src/bin/pdepend"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "PDepend\\": "src/main/php/PDepend"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "description": "Official version of pdepend to be handled with Composer",
+ "keywords": [
+ "PHP Depend",
+ "PHP_Depend",
+ "dev",
+ "pdepend"
+ ],
+ "support": {
+ "issues": "https://github.com/pdepend/pdepend/issues",
+ "source": "https://github.com/pdepend/pdepend/tree/2.16.2"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-12-17T18:09:59+00:00"
},
{
"name": "phar-io/manifest",
@@ -347,13 +555,96 @@
},
"time": "2022-02-21T01:04:05+00:00"
},
+ {
+ "name": "phpmd/phpmd",
+ "version": "2.15.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpmd/phpmd.git",
+ "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpmd/phpmd/zipball/74a1f56e33afad4128b886e334093e98e1b5e7c0",
+ "reference": "74a1f56e33afad4128b886e334093e98e1b5e7c0",
+ "shasum": ""
+ },
+ "require": {
+ "composer/xdebug-handler": "^1.0 || ^2.0 || ^3.0",
+ "ext-xml": "*",
+ "pdepend/pdepend": "^2.16.1",
+ "php": ">=5.3.9"
+ },
+ "require-dev": {
+ "easy-doc/easy-doc": "0.0.0 || ^1.3.2",
+ "ext-json": "*",
+ "ext-simplexml": "*",
+ "gregwar/rst": "^1.0",
+ "mikey179/vfsstream": "^1.6.8",
+ "squizlabs/php_codesniffer": "^2.9.2 || ^3.7.2"
+ },
+ "bin": [
+ "src/bin/phpmd"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "PHPMD\\": "src/main/php"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Manuel Pichler",
+ "email": "github@manuel-pichler.de",
+ "homepage": "https://github.com/manuelpichler",
+ "role": "Project Founder"
+ },
+ {
+ "name": "Marc Würth",
+ "email": "ravage@bluewin.ch",
+ "homepage": "https://github.com/ravage84",
+ "role": "Project Maintainer"
+ },
+ {
+ "name": "Other contributors",
+ "homepage": "https://github.com/phpmd/phpmd/graphs/contributors",
+ "role": "Contributors"
+ }
+ ],
+ "description": "PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.",
+ "homepage": "https://phpmd.org/",
+ "keywords": [
+ "dev",
+ "mess detection",
+ "mess detector",
+ "pdepend",
+ "phpmd",
+ "pmd"
+ ],
+ "support": {
+ "irc": "irc://irc.freenode.org/phpmd",
+ "issues": "https://github.com/phpmd/phpmd/issues",
+ "source": "https://github.com/phpmd/phpmd/tree/2.15.0"
+ },
+ "funding": [
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpmd/phpmd",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2023-12-11T08:22:20+00:00"
+ },
{
"name": "phpstan/phpstan",
- "version": "2.1.31",
+ "version": "2.1.40",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ead89849d879fe203ce9292c6ef5e7e76f867b96",
- "reference": "ead89849d879fe203ce9292c6ef5e7e76f867b96",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b",
+ "reference": "9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b",
"shasum": ""
},
"require": {
@@ -398,27 +689,27 @@
"type": "github"
}
],
- "time": "2025-10-10T14:14:11+00:00"
+ "time": "2026-02-23T15:04:35+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "12.4.0",
+ "version": "12.5.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c"
+ "reference": "b015312f28dd75b75d3422ca37dff2cd1a565e8d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c",
- "reference": "67e8aed88f93d0e6e1cb7effe1a2dfc2fee6022c",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/b015312f28dd75b75d3422ca37dff2cd1a565e8d",
+ "reference": "b015312f28dd75b75d3422ca37dff2cd1a565e8d",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
- "nikic/php-parser": "^5.6.1",
+ "nikic/php-parser": "^5.7.0",
"php": ">=8.3",
"phpunit/php-file-iterator": "^6.0",
"phpunit/php-text-template": "^5.0",
@@ -426,10 +717,10 @@
"sebastian/environment": "^8.0.3",
"sebastian/lines-of-code": "^4.0",
"sebastian/version": "^6.0",
- "theseer/tokenizer": "^1.2.3"
+ "theseer/tokenizer": "^2.0.1"
},
"require-dev": {
- "phpunit/phpunit": "^12.3.7"
+ "phpunit/phpunit": "^12.5.1"
},
"suggest": {
"ext-pcov": "PHP extension that provides line coverage",
@@ -438,7 +729,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "12.4.x-dev"
+ "dev-main": "12.5.x-dev"
}
},
"autoload": {
@@ -467,7 +758,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
- "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.4.0"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.3"
},
"funding": [
{
@@ -487,20 +778,20 @@
"type": "tidelift"
}
],
- "time": "2025-09-24T13:44:41+00:00"
+ "time": "2026-02-06T06:01:44+00:00"
},
{
"name": "phpunit/php-file-iterator",
- "version": "6.0.0",
+ "version": "6.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "961bc913d42fe24a257bfff826a5068079ac7782"
+ "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782",
- "reference": "961bc913d42fe24a257bfff826a5068079ac7782",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5",
+ "reference": "3d1cd096ef6bea4bf2762ba586e35dbd317cbfd5",
"shasum": ""
},
"require": {
@@ -540,15 +831,27 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
- "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0"
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.1"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
+ },
+ {
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/phpunit/php-file-iterator",
+ "type": "tidelift"
}
],
- "time": "2025-02-07T04:58:37+00:00"
+ "time": "2026-02-02T14:04:18+00:00"
},
{
"name": "phpunit/php-invoker",
@@ -736,16 +1039,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "12.4.1",
+ "version": "12.5.14",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "fc5413a2e6d240d2f6d9317bdf7f0a24e73de194"
+ "reference": "47283cfd98d553edcb1353591f4e255dc1bb61f0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc5413a2e6d240d2f6d9317bdf7f0a24e73de194",
- "reference": "fc5413a2e6d240d2f6d9317bdf7f0a24e73de194",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/47283cfd98d553edcb1353591f4e255dc1bb61f0",
+ "reference": "47283cfd98d553edcb1353591f4e255dc1bb61f0",
"shasum": ""
},
"require": {
@@ -759,18 +1062,19 @@
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=8.3",
- "phpunit/php-code-coverage": "^12.4.0",
- "phpunit/php-file-iterator": "^6.0.0",
+ "phpunit/php-code-coverage": "^12.5.3",
+ "phpunit/php-file-iterator": "^6.0.1",
"phpunit/php-invoker": "^6.0.0",
"phpunit/php-text-template": "^5.0.0",
"phpunit/php-timer": "^8.0.0",
"sebastian/cli-parser": "^4.2.0",
- "sebastian/comparator": "^7.1.3",
+ "sebastian/comparator": "^7.1.4",
"sebastian/diff": "^7.0.0",
"sebastian/environment": "^8.0.3",
"sebastian/exporter": "^7.0.2",
"sebastian/global-state": "^8.0.2",
"sebastian/object-enumerator": "^7.0.0",
+ "sebastian/recursion-context": "^7.0.1",
"sebastian/type": "^6.0.3",
"sebastian/version": "^6.0.0",
"staabm/side-effects-detector": "^1.0.5"
@@ -781,7 +1085,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "12.4-dev"
+ "dev-main": "12.5-dev"
}
},
"autoload": {
@@ -813,7 +1117,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/12.4.1"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.14"
},
"funding": [
{
@@ -837,7 +1141,110 @@
"type": "tidelift"
}
],
- "time": "2025-10-09T14:08:29+00:00"
+ "time": "2026-02-18T12:38:40+00:00"
+ },
+ {
+ "name": "psr/container",
+ "version": "2.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/container.git",
+ "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
+ },
+ "dist": {
+ "type": "zip",
+ "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/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common Container Interface (PHP FIG PSR-11)",
+ "homepage": "https://github.com/php-fig/container",
+ "keywords": [
+ "PSR-11",
+ "container",
+ "container-interface",
+ "container-interop",
+ "psr"
+ ],
+ "support": {
+ "issues": "https://github.com/php-fig/container/issues",
+ "source": "https://github.com/php-fig/container/tree/2.0.2"
+ },
+ "time": "2021-11-05T16:47:00+00:00"
+ },
+ {
+ "name": "psr/log",
+ "version": "3.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/log.git",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.0.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Log\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "https://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for logging libraries",
+ "homepage": "https://github.com/php-fig/log",
+ "keywords": [
+ "log",
+ "psr",
+ "psr-3"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/log/tree/3.0.2"
+ },
+ "time": "2024-09-11T13:17:53+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -910,16 +1317,16 @@
},
{
"name": "sebastian/comparator",
- "version": "7.1.3",
+ "version": "7.1.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148"
+ "reference": "6a7de5df2e094f9a80b40a522391a7e6022df5f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dc904b4bb3ab070865fa4068cd84f3da8b945148",
- "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a7de5df2e094f9a80b40a522391a7e6022df5f6",
+ "reference": "6a7de5df2e094f9a80b40a522391a7e6022df5f6",
"shasum": ""
},
"require": {
@@ -978,7 +1385,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"security": "https://github.com/sebastianbergmann/comparator/security/policy",
- "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.3"
+ "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.4"
},
"funding": [
{
@@ -998,7 +1405,7 @@
"type": "tidelift"
}
],
- "time": "2025-08-20T11:27:00+00:00"
+ "time": "2026-01-24T09:28:48+00:00"
},
{
"name": "sebastian/complexity",
@@ -1737,22 +2144,101 @@
"time": "2025-02-07T05:00:38+00:00"
},
{
- "name": "staabm/side-effects-detector",
- "version": "1.0.5",
+ "name": "squizlabs/php_codesniffer",
+ "version": "4.0.1",
"source": {
"type": "git",
- "url": "https://github.com/staabm/side-effects-detector.git",
- "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
+ "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
+ "reference": "0525c73950de35ded110cffafb9892946d7771b5"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
- "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0525c73950de35ded110cffafb9892946d7771b5",
+ "reference": "0525c73950de35ded110cffafb9892946d7771b5",
"shasum": ""
},
"require": {
+ "ext-simplexml": "*",
"ext-tokenizer": "*",
- "php": "^7.4 || ^8.0"
+ "ext-xmlwriter": "*",
+ "php": ">=7.2.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^8.4.0 || ^9.3.4 || ^10.5.32 || 11.3.3 - 11.5.28 || ^11.5.31"
+ },
+ "bin": [
+ "bin/phpcbf",
+ "bin/phpcs"
+ ],
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Greg Sherwood",
+ "role": "Former lead"
+ },
+ {
+ "name": "Juliette Reinders Folmer",
+ "role": "Current lead"
+ },
+ {
+ "name": "Contributors",
+ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors"
+ }
+ ],
+ "description": "PHP_CodeSniffer tokenizes PHP files and detects violations of a defined set of coding standards.",
+ "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
+ "keywords": [
+ "phpcs",
+ "standards",
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues",
+ "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy",
+ "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer",
+ "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/PHPCSStandards",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/jrfnl",
+ "type": "github"
+ },
+ {
+ "url": "https://opencollective.com/php_codesniffer",
+ "type": "open_collective"
+ },
+ {
+ "url": "https://thanks.dev/u/gh/phpcsstandards",
+ "type": "thanks_dev"
+ }
+ ],
+ "time": "2025-11-10T16:43:36+00:00"
+ },
+ {
+ "name": "staabm/side-effects-detector",
+ "version": "1.0.5",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/staabm/side-effects-detector.git",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163",
+ "reference": "d8334211a140ce329c13726d4a715adbddd0a163",
+ "shasum": ""
+ },
+ "require": {
+ "ext-tokenizer": "*",
+ "php": "^7.4 || ^8.0"
},
"require-dev": {
"phpstan/extension-installer": "^1.4.3",
@@ -1788,25 +2274,661 @@
],
"time": "2024-10-20T05:08:20+00:00"
},
+ {
+ "name": "symfony/config",
+ "version": "v7.4.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/config.git",
+ "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/config/zipball/6c17162555bfb58957a55bb0e43e00035b6ae3d5",
+ "reference": "6c17162555bfb58957a55bb0e43e00035b6ae3d5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/filesystem": "^7.1|^8.0",
+ "symfony/polyfill-ctype": "~1.8"
+ },
+ "conflict": {
+ "symfony/finder": "<6.4",
+ "symfony/service-contracts": "<2.5"
+ },
+ "require-dev": {
+ "symfony/event-dispatcher": "^6.4|^7.0|^8.0",
+ "symfony/finder": "^6.4|^7.0|^8.0",
+ "symfony/messenger": "^6.4|^7.0|^8.0",
+ "symfony/service-contracts": "^2.5|^3",
+ "symfony/yaml": "^6.4|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Config\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/config/tree/v7.4.7"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-03-06T10:41:14+00:00"
+ },
+ {
+ "name": "symfony/dependency-injection",
+ "version": "v7.4.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/dependency-injection.git",
+ "reference": "0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db",
+ "reference": "0f651e58f4917fb0e2cd261ccbfe3d71e6e0f5db",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3",
+ "symfony/service-contracts": "^3.6",
+ "symfony/var-exporter": "^6.4.20|^7.2.5|^8.0"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2",
+ "symfony/config": "<6.4",
+ "symfony/finder": "<6.4",
+ "symfony/yaml": "<6.4"
+ },
+ "provide": {
+ "psr/container-implementation": "1.1|2.0",
+ "symfony/service-implementation": "1.1|2.0|3.0"
+ },
+ "require-dev": {
+ "symfony/config": "^6.4|^7.0|^8.0",
+ "symfony/expression-language": "^6.4|^7.0|^8.0",
+ "symfony/yaml": "^6.4|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\DependencyInjection\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Allows you to standardize and centralize the way objects are constructed in your application",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/dependency-injection/tree/v7.4.7"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-03-03T07:48:48+00:00"
+ },
+ {
+ "name": "symfony/deprecation-contracts",
+ "version": "v3.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "function.php"
+ ]
+ },
+ "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": "A generic function and convention to trigger deprecation notices",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.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": "2024-09-25T14:21:43+00:00"
+ },
+ {
+ "name": "symfony/filesystem",
+ "version": "v7.4.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/3ebc794fa5315e59fd122561623c2e2e4280538e",
+ "reference": "3ebc794fa5315e59fd122561623c2e2e4280538e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
+ },
+ "require-dev": {
+ "symfony/process": "^6.4|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides basic utilities for the filesystem",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v7.4.6"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-02-25T16:50:00+00:00"
+ },
+ {
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-ctype": "*"
+ },
+ "suggest": {
+ "ext-ctype": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Ctype\\": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Gert de Pagter",
+ "email": "BackEndTea@gmail.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Symfony polyfill for ctype functions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-09-09T11:45:10+00:00"
+ },
+ {
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "shasum": ""
+ },
+ "require": {
+ "ext-iconv": "*",
+ "php": ">=7.2"
+ },
+ "provide": {
+ "ext-mbstring": "*"
+ },
+ "suggest": {
+ "ext-mbstring": "For best performance"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
+ },
+ "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 for the Mbstring extension",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2024-12-23T08:48:59+00:00"
+ },
+ {
+ "name": "symfony/service-contracts",
+ "version": "v3.6.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/service-contracts.git",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.1",
+ "psr/container": "^1.1|^2.0",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "conflict": {
+ "ext-psr": "<1.1|>=2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "3.6-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Contracts\\Service\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Test/"
+ ]
+ },
+ "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": "Generic abstractions related to writing services",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "abstractions",
+ "contracts",
+ "decoupling",
+ "interfaces",
+ "interoperability",
+ "standards"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-07-15T11:30:57+00:00"
+ },
+ {
+ "name": "symfony/var-exporter",
+ "version": "v7.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/var-exporter.git",
+ "reference": "03a60f169c79a28513a78c967316fbc8bf17816f"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f",
+ "reference": "03a60f169c79a28513a78c967316fbc8bf17816f",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.2",
+ "symfony/deprecation-contracts": "^2.5|^3"
+ },
+ "require-dev": {
+ "symfony/property-access": "^6.4|^7.0|^8.0",
+ "symfony/serializer": "^6.4|^7.0|^8.0",
+ "symfony/var-dumper": "^6.4|^7.0|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\VarExporter\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "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": "Allows exporting any serializable PHP data structure to plain PHP code",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "clone",
+ "construct",
+ "export",
+ "hydrate",
+ "instantiate",
+ "lazy-loading",
+ "proxy",
+ "serialize"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/var-exporter/tree/v7.4.0"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2025-09-11T10:15:23+00:00"
+ },
{
"name": "theseer/tokenizer",
- "version": "1.2.3",
+ "version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4",
+ "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-tokenizer": "*",
"ext-xmlwriter": "*",
- "php": "^7.2 || ^8.0"
+ "php": "^8.1"
},
"type": "library",
"autoload": {
@@ -1828,7 +2950,7 @@
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
- "source": "https://github.com/theseer/tokenizer/tree/1.2.3"
+ "source": "https://github.com/theseer/tokenizer/tree/2.0.1"
},
"funding": [
{
@@ -1836,7 +2958,7 @@
"type": "github"
}
],
- "time": "2024-03-03T12:36:25+00:00"
+ "time": "2025-12-08T11:19:18+00:00"
}
],
"aliases": [],
@@ -1845,8 +2967,8 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": ">=8.2"
+ "php": ">=8.3"
},
"platform-dev": {},
- "plugin-api-version": "2.6.0"
+ "plugin-api-version": "2.9.0"
}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..a01f31d
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,65 @@
+
+
+ Created from PHP.Gt/Styleguide
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpmd.xml b/phpmd.xml
new file mode 100644
index 0000000..983dbd8
--- /dev/null
+++ b/phpmd.xml
@@ -0,0 +1,45 @@
+
+
+ Custom ruleset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/phpunit.xml b/phpunit.xml
index 29ea50e..aacb03a 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,27 +1,28 @@
-
+
+
+ src
+
+
-
-
- ./test/phpunit
-
-
+
-
+
+
+
+ ./test/phpunit/
+
+
+
-
-
- ./src
-
-
+
diff --git a/src/Config.php b/src/Config.php
index bb76da8..9cd2cf2 100644
--- a/src/Config.php
+++ b/src/Config.php
@@ -54,7 +54,8 @@ public function getSectionNames():array {
/**
* Merge another Config into this instance immutably, returning a new Config.
- * Existing values are preserved; only missing keys/sections are filled from the overriding config.
+ * Existing values are preserved.
+ * Only missing keys and sections are filled from the overriding config.
*/
public function withMerge(Config $configToOverride): self {
// Start with current sections
@@ -65,7 +66,7 @@ public function withMerge(Config $configToOverride): self {
if(isset($mergedSectionList[$sectionName])) {
// Fill only missing keys from override into existing section
foreach($overrideSection as $key => $value) {
- if(empty($mergedSectionList[$sectionName][$key])) {
+ if(!$mergedSectionList[$sectionName]->contains($key)) {
$mergedSectionList[$sectionName] = $mergedSectionList[$sectionName]->with($key, $value);
}
}
@@ -80,10 +81,15 @@ public function withMerge(Config $configToOverride): self {
}
/**
- * @deprecated Use withMerge() for an immutable alternative. This method will be removed in a future major release.
+ * @deprecated Use withMerge() for an immutable alternative.
+ * This method will be removed in a future major release.
*/
public function merge(Config $configToOverride):void {
- @trigger_error("Config::merge() is deprecated. Use Config::withMerge() for an immutable merge.", E_USER_DEPRECATED);
+ trigger_error(
+ "Config::merge() is deprecated. "
+ . "Use Config::withMerge() for an immutable merge.",
+ E_USER_DEPRECATED
+ );
$new = $this->withMerge($configToOverride);
$this->sectionList = $new->sectionList;
}
diff --git a/src/ConfigException.php b/src/ConfigException.php
index 6fae3f9..38d50ec 100644
--- a/src/ConfigException.php
+++ b/src/ConfigException.php
@@ -3,4 +3,4 @@
use RuntimeException;
-class ConfigException extends RuntimeException {}
\ No newline at end of file
+class ConfigException extends RuntimeException {}
diff --git a/src/ConfigFactory.php b/src/ConfigFactory.php
index 678299c..759e959 100644
--- a/src/ConfigFactory.php
+++ b/src/ConfigFactory.php
@@ -36,12 +36,12 @@ public static function createForProject(
$fileName .= ".";
}
- $fileName .= self::EXTENSION;
- $config = self::createFromPathName(
- implode(DIRECTORY_SEPARATOR,[
- $projectRoot,
- $fileName,
- ])
+ $fileName .= self::EXTENSION;
+ $config = self::createFromPathName(
+ implode(DIRECTORY_SEPARATOR, [
+ $projectRoot,
+ $fileName,
+ ])
);
if(is_null($config)) {
continue;
diff --git a/src/ConfigSection.php b/src/ConfigSection.php
index ddffa86..226586b 100644
--- a/src/ConfigSection.php
+++ b/src/ConfigSection.php
@@ -2,33 +2,37 @@
namespace Gt\Config;
use ArrayAccess;
+use ArrayIterator;
use BadMethodCallException;
use Gt\TypeSafeGetter\NullableTypeSafeGetter;
-use Iterator;
+use IteratorAggregate;
+use Traversable;
/**
* @implements ArrayAccess
- * @implements Iterator
+ * @implements IteratorAggregate
*/
-class ConfigSection implements ArrayAccess, Iterator {
+class ConfigSection implements ArrayAccess, IteratorAggregate {
use NullableTypeSafeGetter;
protected string $name;
/** @var array */
protected array $data;
- protected int $iteratorIndex;
/** @param array $data */
public function __construct(string $name, array $data) {
$this->name = $name;
$this->data = $data;
- $this->iteratorIndex = 0;
}
public function get(string $name):?string {
return $this->data[$name] ?? null;
}
+ public function contains(string $name):bool {
+ return array_key_exists($name, $this->data);
+ }
+
public function with(string $key, string $value):static {
$clone = clone $this;
$clone->data[$key] = $value;
@@ -36,40 +40,11 @@ public function with(string $key, string $value):static {
}
/**
- * @link http://php.net/manual/en/iterator.current.php
- */
- public function current():string {
- $key = $this->getIteratorKey();
- return $this->data[$key];
- }
-
- /**
- * @link http://php.net/manual/en/iterator.next.php
- */
- public function next():void {
- $this->iteratorIndex++;
- }
-
- /**
- * @link http://php.net/manual/en/iterator.key.php
+ * @return Traversable
+ * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
*/
- public function key():?string {
- return $this->getIteratorKey();
- }
-
- /**
- * @link http://php.net/manual/en/iterator.valid.php
- */
- public function valid():bool {
- $key = $this->getIteratorKey();
- return isset($this->data[$key]);
- }
-
- /**
- * @link http://php.net/manual/en/iterator.rewind.php
- */
- public function rewind():void {
- $this->iteratorIndex = 0;
+ public function getIterator():Traversable {
+ return new ArrayIterator($this->data);
}
/**
@@ -90,22 +65,25 @@ public function offsetGet($offset):?string {
* @link http://php.net/manual/en/arrayaccess.offsetset.php
*/
public function offsetSet($offset, $value):void {
- throw new BadMethodCallException("Immutable object can not be mutated");
+ throw new BadMethodCallException(
+ "Immutable object can not be mutated: "
+ . (string)$offset
+ . "="
+ . (string)$value
+ );
}
/**
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
*/
public function offsetUnset($offset):void {
- throw new BadMethodCallException("Immutable object can not be mutated");
+ throw new BadMethodCallException(
+ "Immutable object can not be mutated: "
+ . (string)$offset
+ );
}
public function getName():string {
return $this->name;
}
-
- protected function getIteratorKey():?string {
- $keys = array_keys($this->data);
- return $keys[$this->iteratorIndex] ?? null;
- }
-}
\ No newline at end of file
+}
diff --git a/src/FileWriter.php b/src/FileWriter.php
index 48cb983..403dce3 100644
--- a/src/FileWriter.php
+++ b/src/FileWriter.php
@@ -35,4 +35,4 @@ public function writeIni(string $filePath):void {
throw new ConfigException("Unable to write to file: $filePath");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Generator.php b/src/Generator.php
index ddc00e7..a4d4391 100644
--- a/src/Generator.php
+++ b/src/Generator.php
@@ -113,4 +113,4 @@ protected function getSectionData(array $sectionList):array {
return $result;
}
-}
\ No newline at end of file
+}
diff --git a/src/IniParser.php b/src/IniParser.php
index 92540b8..370f284 100644
--- a/src/IniParser.php
+++ b/src/IniParser.php
@@ -23,4 +23,4 @@ public function parse():Config {
return new Config(...$configSectionList);
}
-}
\ No newline at end of file
+}
diff --git a/src/InvalidArgumentException.php b/src/InvalidArgumentException.php
index 6404ef5..04d0a93 100644
--- a/src/InvalidArgumentException.php
+++ b/src/InvalidArgumentException.php
@@ -1,4 +1,4 @@
tmp,
+ "config.ini",
+ ]);
+ $filePathDefault = implode(DIRECTORY_SEPARATOR, [
+ $this->tmp,
+ "config.default.ini",
+ ]);
+
+ file_put_contents($filePathDefault, implode(PHP_EOL, [
+ "[session]",
+ "use_cookies=true",
+ "max_age=60",
+ 'label="default"',
+ "",
+ ]));
+ file_put_contents($filePath, implode(PHP_EOL, [
+ "[session]",
+ "use_cookies=false",
+ "max_age=0",
+ 'label=""',
+ "",
+ ]));
+
+ $config = ConfigFactory::createForProject($this->tmp);
+ self::assertFalse($config->getBool("session.use_cookies"));
+ self::assertSame(0, $config->getInt("session.max_age"));
+ self::assertSame("", $config->getString("session.label"));
+ }
}
diff --git a/test/phpunit/ConfigTest.php b/test/phpunit/ConfigTest.php
index 98124c7..edf6433 100644
--- a/test/phpunit/ConfigTest.php
+++ b/test/phpunit/ConfigTest.php
@@ -92,15 +92,19 @@ public function testWithMergeReturnsNewAndDoesNotMutateOriginal():void {
// Ensure new instance returned
self::assertNotSame($original, $merged);
- // Original remains unchanged (use section access to avoid env var interference)
- self::assertSame("ExampleAppOriginal", $original->getSection("app")->get("namespace"));
- self::assertNull($original->getSection("app")->get("extra"));
- self::assertNull($original->getSection("cache"));
-
- // Merged config has expected values
- self::assertSame("ExampleAppOriginal", $merged->getSection("app")->get("namespace")); // existing preserved
- self::assertSame("value", $merged->getSection("app")->get("extra")); // new key added
- self::assertSame("1", $merged->getSection("cache")->get("enabled")); // new section added
+ // Original remains unchanged.
+ // Use section access to avoid env var interference.
+ self::assertSame("ExampleAppOriginal", $original->getSection("app")->get("namespace"));
+ self::assertNull($original->getSection("app")->get("extra"));
+ self::assertNull($original->getSection("cache"));
+
+ // Merged config has expected values
+ self::assertSame(
+ "ExampleAppOriginal",
+ $merged->getSection("app")->get("namespace")
+ ); // existing preserved
+ self::assertSame("value", $merged->getSection("app")->get("extra")); // new key added
+ self::assertSame("1", $merged->getSection("cache")->get("enabled")); // new section added
}
public function testMergeEmitsDeprecationAndMutates():void {
@@ -118,6 +122,7 @@ public function testMergeEmitsDeprecationAndMutates():void {
$deprecationCount = 0;
set_error_handler(function(int $errno, string $errstr) use (&$deprecationCount) {
if($errno === E_USER_DEPRECATED) {
+ self::assertStringContainsString("Config::merge() is deprecated", $errstr);
$deprecationCount++;
}
return true; // prevent PHPUnit from handling
diff --git a/test/phpunit/GeneratorConfigTest.php b/test/phpunit/GeneratorConfigTest.php
index db0a2ef..5c443bf 100644
--- a/test/phpunit/GeneratorConfigTest.php
+++ b/test/phpunit/GeneratorConfigTest.php
@@ -29,7 +29,7 @@ public function testGenerateDisallowedSuffix() {
new Generator(["config-generate", "meow", "test"]);
}
- public function testGenerateNoKVP() {
+ public function testGenerateNoKvp() {
self::expectException(InvalidArgumentException::class);
self::expectExceptionMessage("Invalid key-value pair: test");
new Generator(["config-generate", "dev", "test"]);
@@ -38,11 +38,15 @@ public function testGenerateNoKVP() {
public function testGenerateNoSection() {
self::expectException(InvalidArgumentException::class);
self::expectExceptionMessage("Invalid key-value pair: testkey");
- $sut = new Generator(["config-generate", "dev", "testkey=testvalue"]);
+ new Generator(["config-generate", "dev", "testkey=testvalue"]);
}
public function testGenerate() {
- $sut = new Generator(["config-generate", "dev", "testsection.testkey=testvalue"]);
+ $sut = new Generator([
+ "config-generate",
+ "dev",
+ "testsection.testkey=testvalue",
+ ]);
$sut->generate();
$filePath = $this->tmp . "/config.dev.ini";
self::assertFileExists($filePath);
diff --git a/test/phpunit/Helper/Helper.php b/test/phpunit/Helper/Helper.php
index ab7dadd..b674939 100644
--- a/test/phpunit/Helper/Helper.php
+++ b/test/phpunit/Helper/Helper.php
@@ -86,4 +86,4 @@ public static function recursiveRemove(string $dir) {
rmdir($dir);
}
-}
\ No newline at end of file
+}