diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..deb7326
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,28 @@
+name: "Tests"
+
+on:
+ pull_request:
+ push:
+ branches:
+ - main
+
+jobs:
+ tests:
+ name: Tests (PHP ${{ matrix.php }})
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ php: ['8.2', '8.3', '8.4']
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: Run tests
+ run: |
+ PHP_VERSION=${{ matrix.php }} docker compose run --rm tests sh -c "
+ git config --global --add safe.directory /app &&
+ composer update --no-interaction &&
+ composer test
+ "
\ No newline at end of file
diff --git a/composer.json b/composer.json
index 59b9dc0..b71d94c 100644
--- a/composer.json
+++ b/composer.json
@@ -13,6 +13,11 @@
"Utopia\\Telemetry\\": "src/Telemetry"
}
},
+ "autoload-dev": {
+ "psr-4": {
+ "Tests\\Telemetry\\": "tests/Telemetry"
+ }
+ },
"scripts": {
"lint": "vendor/bin/pint --test",
"format": "vendor/bin/pint",
@@ -24,16 +29,21 @@
"ext-protobuf": "*",
"ext-opentelemetry": "*",
"php": ">=8.0",
- "open-telemetry/sdk": "^1.1",
- "symfony/http-client": "^7.1",
- "nyholm/psr7": "^1.8",
- "open-telemetry/exporter-otlp": "^1.1"
+ "nyholm/psr7": "1.*",
+ "open-telemetry/exporter-otlp": "1.*",
+ "open-telemetry/sdk": "1.*",
+ "symfony/http-client": "7.*"
},
"require-dev": {
- "phpunit/phpunit": "^9.5.25",
- "laravel/pint": "^1.2",
- "phpstan/phpstan": "^1.10",
- "phpbench/phpbench": "^1.2"
+ "phpunit/phpunit": "11.*",
+ "laravel/pint": "1.*",
+ "phpstan/phpstan": "2.*",
+ "phpbench/phpbench": "1.*",
+ "swoole/ide-helper": "6.*"
+ },
+ "suggest": {
+ "ext-swoole": "Required for the Swoole transport implementation",
+ "ext-sockets": "Required for the Swoole transport implementation"
},
"config": {
"allow-plugins": {
diff --git a/composer.lock b/composer.lock
index f6ba6c5..557d4e3 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,29 +4,29 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "656715b7623d3d2bfb431be7547348db",
+ "content-hash": "0d94b4c877d8d2acc33c4ff2fc91c560",
"packages": [
{
"name": "brick/math",
- "version": "0.12.3",
+ "version": "0.14.1",
"source": {
"type": "git",
"url": "https://github.com/brick/math.git",
- "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba"
+ "reference": "f05858549e5f9d7bb45875a75583240a38a281d0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba",
- "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba",
+ "url": "https://api.github.com/repos/brick/math/zipball/f05858549e5f9d7bb45875a75583240a38a281d0",
+ "reference": "f05858549e5f9d7bb45875a75583240a38a281d0",
"shasum": ""
},
"require": {
- "php": "^8.1"
+ "php": "^8.2"
},
"require-dev": {
"php-coveralls/php-coveralls": "^2.2",
- "phpunit/phpunit": "^10.1",
- "vimeo/psalm": "6.8.8"
+ "phpstan/phpstan": "2.1.22",
+ "phpunit/phpunit": "^11.5"
},
"type": "library",
"autoload": {
@@ -56,7 +56,7 @@
],
"support": {
"issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.12.3"
+ "source": "https://github.com/brick/math/tree/0.14.1"
},
"funding": [
{
@@ -64,20 +64,20 @@
"type": "github"
}
],
- "time": "2025-02-28T13:11:00+00:00"
+ "time": "2025-11-24T14:40:29+00:00"
},
{
"name": "composer/semver",
- "version": "3.4.3",
+ "version": "3.4.4",
"source": {
"type": "git",
"url": "https://github.com/composer/semver.git",
- "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12"
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
- "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12",
+ "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95",
+ "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95",
"shasum": ""
},
"require": {
@@ -129,7 +129,7 @@
"support": {
"irc": "ircs://irc.libera.chat:6697/composer",
"issues": "https://github.com/composer/semver/issues",
- "source": "https://github.com/composer/semver/tree/3.4.3"
+ "source": "https://github.com/composer/semver/tree/3.4.4"
},
"funding": [
{
@@ -139,33 +139,29 @@
{
"url": "https://github.com/composer",
"type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/composer/composer",
- "type": "tidelift"
}
],
- "time": "2024-09-19T14:15:21+00:00"
+ "time": "2025-08-20T19:15:30+00:00"
},
{
"name": "google/protobuf",
- "version": "v4.30.1",
+ "version": "v4.33.2",
"source": {
"type": "git",
"url": "https://github.com/protocolbuffers/protobuf-php.git",
- "reference": "f29ba8a30dfd940efb3a8a75dc44446539101f24"
+ "reference": "fbd96b7bf1343f4b0d8fb358526c7ba4d72f1318"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/f29ba8a30dfd940efb3a8a75dc44446539101f24",
- "reference": "f29ba8a30dfd940efb3a8a75dc44446539101f24",
+ "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/fbd96b7bf1343f4b0d8fb358526c7ba4d72f1318",
+ "reference": "fbd96b7bf1343f4b0d8fb358526c7ba4d72f1318",
"shasum": ""
},
"require": {
- "php": ">=7.0.0"
+ "php": ">=8.1.0"
},
"require-dev": {
- "phpunit/phpunit": ">=5.0.0"
+ "phpunit/phpunit": ">=5.0.0 <8.5.27"
},
"suggest": {
"ext-bcmath": "Need to support JSON deserialization"
@@ -187,9 +183,9 @@
"proto"
],
"support": {
- "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.30.1"
+ "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.2"
},
- "time": "2025-03-13T21:08:17+00:00"
+ "time": "2025-12-05T22:12:22+00:00"
},
{
"name": "nyholm/psr7",
@@ -337,20 +333,20 @@
},
{
"name": "open-telemetry/api",
- "version": "1.2.3",
+ "version": "1.7.1",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/api.git",
- "reference": "199d7ddda88f5f5619fa73463f1a5a7149ccd1f1"
+ "reference": "45bda7efa8fcdd9bdb0daa2f26c8e31f062f49d4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/api/zipball/199d7ddda88f5f5619fa73463f1a5a7149ccd1f1",
- "reference": "199d7ddda88f5f5619fa73463f1a5a7149ccd1f1",
+ "url": "https://api.github.com/repos/opentelemetry-php/api/zipball/45bda7efa8fcdd9bdb0daa2f26c8e31f062f49d4",
+ "reference": "45bda7efa8fcdd9bdb0daa2f26c8e31f062f49d4",
"shasum": ""
},
"require": {
- "open-telemetry/context": "^1.0",
+ "open-telemetry/context": "^1.4",
"php": "^8.1",
"psr/log": "^1.1|^2.0|^3.0",
"symfony/polyfill-php82": "^1.26"
@@ -366,7 +362,7 @@
]
},
"branch-alias": {
- "dev-main": "1.1.x-dev"
+ "dev-main": "1.8.x-dev"
}
},
"autoload": {
@@ -399,24 +395,24 @@
],
"support": {
"chat": "https://app.slack.com/client/T08PSQ7BQ/C01NFPCV44V",
- "docs": "https://opentelemetry.io/docs/php",
+ "docs": "https://opentelemetry.io/docs/languages/php",
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-03-05T21:42:54+00:00"
+ "time": "2025-10-19T10:49:48+00:00"
},
{
"name": "open-telemetry/context",
- "version": "1.1.0",
+ "version": "1.4.0",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/context.git",
- "reference": "0cba875ea1953435f78aec7f1d75afa87bdbf7f3"
+ "reference": "d4c4470b541ce72000d18c339cfee633e4c8e0cf"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/context/zipball/0cba875ea1953435f78aec7f1d75afa87bdbf7f3",
- "reference": "0cba875ea1953435f78aec7f1d75afa87bdbf7f3",
+ "url": "https://api.github.com/repos/opentelemetry-php/context/zipball/d4c4470b541ce72000d18c339cfee633e4c8e0cf",
+ "reference": "d4c4470b541ce72000d18c339cfee633e4c8e0cf",
"shasum": ""
},
"require": {
@@ -462,20 +458,20 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2024-08-21T00:29:20+00:00"
+ "time": "2025-09-19T00:05:49+00:00"
},
{
"name": "open-telemetry/exporter-otlp",
- "version": "1.2.1",
+ "version": "1.3.3",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/exporter-otlp.git",
- "reference": "b7580440b7481a98da97aceabeb46e1b276c8747"
+ "reference": "07b02bc71838463f6edcc78d3485c04b48fb263d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/b7580440b7481a98da97aceabeb46e1b276c8747",
- "reference": "b7580440b7481a98da97aceabeb46e1b276c8747",
+ "url": "https://api.github.com/repos/opentelemetry-php/exporter-otlp/zipball/07b02bc71838463f6edcc78d3485c04b48fb263d",
+ "reference": "07b02bc71838463f6edcc78d3485c04b48fb263d",
"shasum": ""
},
"require": {
@@ -522,24 +518,24 @@
],
"support": {
"chat": "https://app.slack.com/client/T08PSQ7BQ/C01NFPCV44V",
- "docs": "https://opentelemetry.io/docs/php",
+ "docs": "https://opentelemetry.io/docs/languages/php",
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-03-06T23:21:56+00:00"
+ "time": "2025-11-13T08:04:37+00:00"
},
{
"name": "open-telemetry/gen-otlp-protobuf",
- "version": "1.5.0",
+ "version": "1.8.0",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/gen-otlp-protobuf.git",
- "reference": "585bafddd4ae6565de154610b10a787a455c9ba0"
+ "reference": "673af5b06545b513466081884b47ef15a536edde"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/gen-otlp-protobuf/zipball/585bafddd4ae6565de154610b10a787a455c9ba0",
- "reference": "585bafddd4ae6565de154610b10a787a455c9ba0",
+ "url": "https://api.github.com/repos/opentelemetry-php/gen-otlp-protobuf/zipball/673af5b06545b513466081884b47ef15a536edde",
+ "reference": "673af5b06545b513466081884b47ef15a536edde",
"shasum": ""
},
"require": {
@@ -589,27 +585,27 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-01-15T23:07:07+00:00"
+ "time": "2025-09-17T23:10:12+00:00"
},
{
"name": "open-telemetry/sdk",
- "version": "1.2.2",
+ "version": "1.10.0",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sdk.git",
- "reference": "37eec0fe47ddd627911f318f29b6cd48196be0c0"
+ "reference": "3dfc3d1ad729ec7eb25f1b9a4ae39fe779affa99"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/37eec0fe47ddd627911f318f29b6cd48196be0c0",
- "reference": "37eec0fe47ddd627911f318f29b6cd48196be0c0",
+ "url": "https://api.github.com/repos/opentelemetry-php/sdk/zipball/3dfc3d1ad729ec7eb25f1b9a4ae39fe779affa99",
+ "reference": "3dfc3d1ad729ec7eb25f1b9a4ae39fe779affa99",
"shasum": ""
},
"require": {
"ext-json": "*",
"nyholm/psr7-server": "^1.1",
- "open-telemetry/api": "~1.0 || ~1.1",
- "open-telemetry/context": "^1.0",
+ "open-telemetry/api": "^1.7",
+ "open-telemetry/context": "^1.4",
"open-telemetry/sem-conv": "^1.0",
"php": "^8.1",
"php-http/discovery": "^1.14",
@@ -621,7 +617,7 @@
"ramsey/uuid": "^3.0 || ^4.0",
"symfony/polyfill-mbstring": "^1.23",
"symfony/polyfill-php82": "^1.26",
- "tbachert/spi": "^1.0.1"
+ "tbachert/spi": "^1.0.5"
},
"suggest": {
"ext-gmp": "To support unlimited number of synchronous metric readers",
@@ -631,12 +627,19 @@
"type": "library",
"extra": {
"spi": {
+ "OpenTelemetry\\API\\Configuration\\ConfigEnv\\EnvComponentLoader": [
+ "OpenTelemetry\\API\\Instrumentation\\Configuration\\General\\ConfigEnv\\EnvComponentLoaderHttpConfig",
+ "OpenTelemetry\\API\\Instrumentation\\Configuration\\General\\ConfigEnv\\EnvComponentLoaderPeerConfig"
+ ],
+ "OpenTelemetry\\SDK\\Common\\Configuration\\Resolver\\ResolverInterface": [
+ "OpenTelemetry\\SDK\\Common\\Configuration\\Resolver\\SdkConfigurationResolver"
+ ],
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\HookManagerInterface": [
"OpenTelemetry\\API\\Instrumentation\\AutoInstrumentation\\ExtensionHookManager"
]
},
"branch-alias": {
- "dev-main": "1.0.x-dev"
+ "dev-main": "1.9.x-dev"
}
},
"autoload": {
@@ -675,24 +678,24 @@
],
"support": {
"chat": "https://app.slack.com/client/T08PSQ7BQ/C01NFPCV44V",
- "docs": "https://opentelemetry.io/docs/php",
+ "docs": "https://opentelemetry.io/docs/languages/php",
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-01-29T21:40:28+00:00"
+ "time": "2025-11-25T10:59:15+00:00"
},
{
"name": "open-telemetry/sem-conv",
- "version": "1.30.0",
+ "version": "1.37.0",
"source": {
"type": "git",
"url": "https://github.com/opentelemetry-php/sem-conv.git",
- "reference": "4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a"
+ "reference": "8da7ec497c881e39afa6657d72586e27efbd29a1"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a",
- "reference": "4178c9f390da8e4dbca9b181a9d1efd50cf7ee0a",
+ "url": "https://api.github.com/repos/opentelemetry-php/sem-conv/zipball/8da7ec497c881e39afa6657d72586e27efbd29a1",
+ "reference": "8da7ec497c881e39afa6657d72586e27efbd29a1",
"shasum": ""
},
"require": {
@@ -736,7 +739,7 @@
"issues": "https://github.com/open-telemetry/opentelemetry-php/issues",
"source": "https://github.com/open-telemetry/opentelemetry-php"
},
- "time": "2025-02-06T00:21:48+00:00"
+ "time": "2025-09-03T12:08:10+00:00"
},
{
"name": "php-http/discovery",
@@ -1082,16 +1085,16 @@
},
{
"name": "ramsey/collection",
- "version": "2.1.0",
+ "version": "2.1.1",
"source": {
"type": "git",
"url": "https://github.com/ramsey/collection.git",
- "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109"
+ "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/collection/zipball/3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
- "reference": "3c5990b8a5e0b79cd1cf11c2dc1229e58e93f109",
+ "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2",
+ "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2",
"shasum": ""
},
"require": {
@@ -1152,27 +1155,26 @@
],
"support": {
"issues": "https://github.com/ramsey/collection/issues",
- "source": "https://github.com/ramsey/collection/tree/2.1.0"
+ "source": "https://github.com/ramsey/collection/tree/2.1.1"
},
- "time": "2025-03-02T04:48:29+00:00"
+ "time": "2025-03-22T05:38:12+00:00"
},
{
"name": "ramsey/uuid",
- "version": "4.7.6",
+ "version": "4.9.2",
"source": {
"type": "git",
"url": "https://github.com/ramsey/uuid.git",
- "reference": "91039bc1faa45ba123c4328958e620d382ec7088"
+ "reference": "8429c78ca35a09f27565311b98101e2826affde0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/ramsey/uuid/zipball/91039bc1faa45ba123c4328958e620d382ec7088",
- "reference": "91039bc1faa45ba123c4328958e620d382ec7088",
+ "url": "https://api.github.com/repos/ramsey/uuid/zipball/8429c78ca35a09f27565311b98101e2826affde0",
+ "reference": "8429c78ca35a09f27565311b98101e2826affde0",
"shasum": ""
},
"require": {
- "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12",
- "ext-json": "*",
+ "brick/math": "^0.8.16 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14",
"php": "^8.0",
"ramsey/collection": "^1.2 || ^2.0"
},
@@ -1180,26 +1182,23 @@
"rhumsaa/uuid": "self.version"
},
"require-dev": {
- "captainhook/captainhook": "^5.10",
+ "captainhook/captainhook": "^5.25",
"captainhook/plugin-composer": "^5.3",
- "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
- "doctrine/annotations": "^1.8",
- "ergebnis/composer-normalize": "^2.15",
- "mockery/mockery": "^1.3",
+ "dealerdirect/phpcodesniffer-composer-installer": "^1.0",
+ "ergebnis/composer-normalize": "^2.47",
+ "mockery/mockery": "^1.6",
"paragonie/random-lib": "^2",
- "php-mock/php-mock": "^2.2",
- "php-mock/php-mock-mockery": "^1.3",
- "php-parallel-lint/php-parallel-lint": "^1.1",
- "phpbench/phpbench": "^1.0",
- "phpstan/extension-installer": "^1.1",
- "phpstan/phpstan": "^1.8",
- "phpstan/phpstan-mockery": "^1.1",
- "phpstan/phpstan-phpunit": "^1.1",
- "phpunit/phpunit": "^8.5 || ^9",
- "ramsey/composer-repl": "^1.4",
- "slevomat/coding-standard": "^8.4",
- "squizlabs/php_codesniffer": "^3.5",
- "vimeo/psalm": "^4.9"
+ "php-mock/php-mock": "^2.6",
+ "php-mock/php-mock-mockery": "^1.5",
+ "php-parallel-lint/php-parallel-lint": "^1.4.0",
+ "phpbench/phpbench": "^1.2.14",
+ "phpstan/extension-installer": "^1.4",
+ "phpstan/phpstan": "^2.1",
+ "phpstan/phpstan-mockery": "^2.0",
+ "phpstan/phpstan-phpunit": "^2.0",
+ "phpunit/phpunit": "^9.6",
+ "slevomat/coding-standard": "^8.18",
+ "squizlabs/php_codesniffer": "^3.13"
},
"suggest": {
"ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.",
@@ -1234,32 +1233,22 @@
],
"support": {
"issues": "https://github.com/ramsey/uuid/issues",
- "source": "https://github.com/ramsey/uuid/tree/4.7.6"
+ "source": "https://github.com/ramsey/uuid/tree/4.9.2"
},
- "funding": [
- {
- "url": "https://github.com/ramsey",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid",
- "type": "tidelift"
- }
- ],
- "time": "2024-04-27T21:32:50+00:00"
+ "time": "2025-12-14T04:43:48+00:00"
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.5.1",
+ "version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
- "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
+ "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
"shasum": ""
},
"require": {
@@ -1272,7 +1261,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
- "dev-main": "3.5-dev"
+ "dev-main": "3.6-dev"
}
},
"autoload": {
@@ -1297,7 +1286,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
},
"funding": [
{
@@ -1313,20 +1302,20 @@
"type": "tidelift"
}
],
- "time": "2024-09-25T14:20:29+00:00"
+ "time": "2024-09-25T14:21:43+00:00"
},
{
"name": "symfony/http-client",
- "version": "v7.2.4",
+ "version": "v7.4.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client.git",
- "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6"
+ "reference": "26cc224ea7103dda90e9694d9e139a389092d007"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client/zipball/78981a2ffef6437ed92d4d7e2a86a82f256c6dc6",
- "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6",
+ "url": "https://api.github.com/repos/symfony/http-client/zipball/26cc224ea7103dda90e9694d9e139a389092d007",
+ "reference": "26cc224ea7103dda90e9694d9e139a389092d007",
"shasum": ""
},
"require": {
@@ -1334,10 +1323,12 @@
"psr/log": "^1|^2|^3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/http-client-contracts": "~3.4.4|^3.5.2",
+ "symfony/polyfill-php83": "^1.29",
"symfony/service-contracts": "^2.5|^3"
},
"conflict": {
"amphp/amp": "<2.5",
+ "amphp/socket": "<1.1",
"php-http/discovery": "<1.15",
"symfony/http-foundation": "<6.4"
},
@@ -1350,18 +1341,18 @@
"require-dev": {
"amphp/http-client": "^4.2.1|^5.0",
"amphp/http-tunnel": "^1.0|^2.0",
- "amphp/socket": "^1.1",
"guzzlehttp/promises": "^1.4|^2.0",
"nyholm/psr7": "^1.0",
"php-http/httplug": "^1.0|^2.0",
"psr/http-client": "^1.0",
"symfony/amphp-http-client-meta": "^1.0|^2.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/rate-limiter": "^6.4|^7.0",
- "symfony/stopwatch": "^6.4|^7.0"
+ "symfony/cache": "^6.4|^7.0|^8.0",
+ "symfony/dependency-injection": "^6.4|^7.0|^8.0",
+ "symfony/http-kernel": "^6.4|^7.0|^8.0",
+ "symfony/messenger": "^6.4|^7.0|^8.0",
+ "symfony/process": "^6.4|^7.0|^8.0",
+ "symfony/rate-limiter": "^6.4|^7.0|^8.0",
+ "symfony/stopwatch": "^6.4|^7.0|^8.0"
},
"type": "library",
"autoload": {
@@ -1392,7 +1383,7 @@
"http"
],
"support": {
- "source": "https://github.com/symfony/http-client/tree/v7.2.4"
+ "source": "https://github.com/symfony/http-client/tree/v7.4.1"
},
"funding": [
{
@@ -1403,25 +1394,29 @@
"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-02-13T10:27:23+00:00"
+ "time": "2025-12-04T21:12:57+00:00"
},
{
"name": "symfony/http-client-contracts",
- "version": "v3.5.2",
+ "version": "v3.6.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-client-contracts.git",
- "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645"
+ "reference": "75d7043853a42837e68111812f4d964b01e5101c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645",
- "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645",
+ "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c",
+ "reference": "75d7043853a42837e68111812f4d964b01e5101c",
"shasum": ""
},
"require": {
@@ -1434,7 +1429,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
- "dev-main": "3.5-dev"
+ "dev-main": "3.6-dev"
}
},
"autoload": {
@@ -1470,7 +1465,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.2"
+ "source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0"
},
"funding": [
{
@@ -1486,23 +1481,24 @@
"type": "tidelift"
}
],
- "time": "2024-12-07T08:49:48+00:00"
+ "time": "2025-04-29T11:18:49+00:00"
},
{
"name": "symfony/polyfill-mbstring",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
- "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493",
+ "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493",
"shasum": ""
},
"require": {
+ "ext-iconv": "*",
"php": ">=7.2"
},
"provide": {
@@ -1550,7 +1546,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0"
},
"funding": [
{
@@ -1561,16 +1557,20 @@
"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"
+ "time": "2024-12-23T08:48:59+00:00"
},
{
"name": "symfony/polyfill-php82",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php82.git",
@@ -1626,7 +1626,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-php82/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-php82/tree/v1.33.0"
},
"funding": [
{
@@ -1637,6 +1637,10 @@
"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"
@@ -1644,18 +1648,98 @@
],
"time": "2024-09-09T11:45:10+00:00"
},
+ {
+ "name": "symfony/polyfill-php83",
+ "version": "v1.33.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/polyfill-php83.git",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=7.2"
+ },
+ "type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
+ "autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
+ "psr-4": {
+ "Symfony\\Polyfill\\Php83\\": ""
+ },
+ "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 8.3+ features to lower PHP versions",
+ "homepage": "https://symfony.com",
+ "keywords": [
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
+ ],
+ "support": {
+ "source": "https://github.com/symfony/polyfill-php83/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": "2025-07-08T02:45:35+00:00"
+ },
{
"name": "symfony/service-contracts",
- "version": "v3.5.1",
+ "version": "v3.6.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0"
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
- "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
+ "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
"shasum": ""
},
"require": {
@@ -1673,7 +1757,7 @@
"name": "symfony/contracts"
},
"branch-alias": {
- "dev-main": "3.5-dev"
+ "dev-main": "3.6-dev"
}
},
"autoload": {
@@ -1709,7 +1793,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.5.1"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
},
"funding": [
{
@@ -1720,25 +1804,29 @@
"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-25T14:20:29+00:00"
+ "time": "2025-07-15T11:30:57+00:00"
},
{
"name": "tbachert/spi",
- "version": "v1.0.2",
+ "version": "v1.0.5",
"source": {
"type": "git",
"url": "https://github.com/Nevay/spi.git",
- "reference": "2ddfaf815dafb45791a61b08170de8d583c16062"
+ "reference": "e7078767866d0a9e0f91d3f9d42a832df5e39002"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/Nevay/spi/zipball/2ddfaf815dafb45791a61b08170de8d583c16062",
- "reference": "2ddfaf815dafb45791a61b08170de8d583c16062",
+ "url": "https://api.github.com/repos/Nevay/spi/zipball/e7078767866d0a9e0f91d3f9d42a832df5e39002",
+ "reference": "e7078767866d0a9e0f91d3f9d42a832df5e39002",
"shasum": ""
},
"require": {
@@ -1756,7 +1844,7 @@
"extra": {
"class": "Nevay\\SPI\\Composer\\Plugin",
"branch-alias": {
- "dev-main": "0.2.x-dev"
+ "dev-main": "1.0.x-dev"
},
"plugin-optional": true
},
@@ -1775,9 +1863,9 @@
],
"support": {
"issues": "https://github.com/Nevay/spi/issues",
- "source": "https://github.com/Nevay/spi/tree/v1.0.2"
+ "source": "https://github.com/Nevay/spi/tree/v1.0.5"
},
- "time": "2024-10-04T16:36:12+00:00"
+ "time": "2025-06-29T15:42:06+00:00"
}
],
"packages-dev": [
@@ -1855,78 +1943,9 @@
"issues": "https://github.com/doctrine/annotations/issues",
"source": "https://github.com/doctrine/annotations/tree/2.0.2"
},
+ "abandoned": true,
"time": "2024-09-05T10:17:24+00:00"
},
- {
- "name": "doctrine/instantiator",
- "version": "2.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/doctrine/instantiator.git",
- "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
- "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0",
- "shasum": ""
- },
- "require": {
- "php": "^8.1"
- },
- "require-dev": {
- "doctrine/coding-standard": "^11",
- "ext-pdo": "*",
- "ext-phar": "*",
- "phpbench/phpbench": "^1.2",
- "phpstan/phpstan": "^1.9.4",
- "phpstan/phpstan-phpunit": "^1.3",
- "phpunit/phpunit": "^9.5.27",
- "vimeo/psalm": "^5.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Marco Pivetta",
- "email": "ocramius@gmail.com",
- "homepage": "https://ocramius.github.io/"
- }
- ],
- "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
- "homepage": "https://www.doctrine-project.org/projects/instantiator.html",
- "keywords": [
- "constructor",
- "instantiate"
- ],
- "support": {
- "issues": "https://github.com/doctrine/instantiator/issues",
- "source": "https://github.com/doctrine/instantiator/tree/2.0.0"
- },
- "funding": [
- {
- "url": "https://www.doctrine-project.org/sponsorship.html",
- "type": "custom"
- },
- {
- "url": "https://www.patreon.com/phpdoctrine",
- "type": "patreon"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator",
- "type": "tidelift"
- }
- ],
- "time": "2022-12-30T00:23:10+00:00"
- },
{
"name": "doctrine/lexer",
"version": "3.0.1",
@@ -2006,16 +2025,16 @@
},
{
"name": "laravel/pint",
- "version": "v1.21.2",
+ "version": "v1.26.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/pint.git",
- "reference": "370772e7d9e9da087678a0edf2b11b6960e40558"
+ "reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/laravel/pint/zipball/370772e7d9e9da087678a0edf2b11b6960e40558",
- "reference": "370772e7d9e9da087678a0edf2b11b6960e40558",
+ "url": "https://api.github.com/repos/laravel/pint/zipball/69dcca060ecb15e4b564af63d1f642c81a241d6f",
+ "reference": "69dcca060ecb15e4b564af63d1f642c81a241d6f",
"shasum": ""
},
"require": {
@@ -2026,13 +2045,13 @@
"php": "^8.2.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^3.72.0",
- "illuminate/view": "^11.44.2",
- "larastan/larastan": "^3.2.0",
- "laravel-zero/framework": "^11.36.1",
+ "friendsofphp/php-cs-fixer": "^3.90.0",
+ "illuminate/view": "^12.40.1",
+ "larastan/larastan": "^3.8.0",
+ "laravel-zero/framework": "^12.0.4",
"mockery/mockery": "^1.6.12",
- "nunomaduro/termwind": "^2.3",
- "pestphp/pest": "^2.36.0"
+ "nunomaduro/termwind": "^2.3.3",
+ "pestphp/pest": "^3.8.4"
},
"bin": [
"builds/pint"
@@ -2058,6 +2077,7 @@
"description": "An opinionated code formatter for PHP.",
"homepage": "https://laravel.com",
"keywords": [
+ "dev",
"format",
"formatter",
"lint",
@@ -2068,20 +2088,20 @@
"issues": "https://github.com/laravel/pint/issues",
"source": "https://github.com/laravel/pint"
},
- "time": "2025-03-14T22:31:42+00:00"
+ "time": "2025-11-25T21:15:52+00:00"
},
{
"name": "myclabs/deep-copy",
- "version": "1.13.0",
+ "version": "1.13.4",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "024473a478be9df5fdaca2c793f2232fe788e414"
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
- "reference": "024473a478be9df5fdaca2c793f2232fe788e414",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a",
+ "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a",
"shasum": ""
},
"require": {
@@ -2120,7 +2140,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4"
},
"funding": [
{
@@ -2128,20 +2148,20 @@
"type": "tidelift"
}
],
- "time": "2025-02-12T12:17:51+00:00"
+ "time": "2025-08-01T08:46:24+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v5.4.0",
+ "version": "v5.7.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "447a020a1f875a434d62f2a401f53b82a396e494"
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
- "reference": "447a020a1f875a434d62f2a401f53b82a396e494",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+ "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
"shasum": ""
},
"require": {
@@ -2160,7 +2180,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-master": "5.x-dev"
}
},
"autoload": {
@@ -2184,9 +2204,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
},
- "time": "2024-12-30T11:07:19+00:00"
+ "time": "2025-12-06T11:56:16+00:00"
},
{
"name": "phar-io/manifest",
@@ -2308,24 +2328,24 @@
},
{
"name": "phpbench/container",
- "version": "2.2.2",
+ "version": "2.2.3",
"source": {
"type": "git",
"url": "https://github.com/phpbench/container.git",
- "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33"
+ "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/container/zipball/a59b929e00b87b532ca6d0edd8eca0967655af33",
- "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33",
+ "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196",
+ "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196",
"shasum": ""
},
"require": {
"psr/container": "^1.0|^2.0",
- "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0"
+ "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0"
},
"require-dev": {
- "friendsofphp/php-cs-fixer": "^2.16",
+ "php-cs-fixer/shim": "^3.89",
"phpstan/phpstan": "^0.12.52",
"phpunit/phpunit": "^8"
},
@@ -2353,22 +2373,22 @@
"description": "Simple, configurable, service container.",
"support": {
"issues": "https://github.com/phpbench/container/issues",
- "source": "https://github.com/phpbench/container/tree/2.2.2"
+ "source": "https://github.com/phpbench/container/tree/2.2.3"
},
- "time": "2023-10-30T13:38:26+00:00"
+ "time": "2025-11-06T09:05:13+00:00"
},
{
"name": "phpbench/phpbench",
- "version": "1.4.1",
+ "version": "1.4.3",
"source": {
"type": "git",
"url": "https://github.com/phpbench/phpbench.git",
- "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b"
+ "reference": "b641dde59d969ea42eed70a39f9b51950bc96878"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpbench/phpbench/zipball/78cd98a9aa34e0f8f80ca01972a8b88d2c30194b",
- "reference": "78cd98a9aa34e0f8f80ca01972a8b88d2c30194b",
+ "url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878",
+ "reference": "b641dde59d969ea42eed70a39f9b51950bc96878",
"shasum": ""
},
"require": {
@@ -2383,26 +2403,26 @@
"phpbench/container": "^2.2",
"psr/log": "^1.1 || ^2.0 || ^3.0",
"seld/jsonlint": "^1.1",
- "symfony/console": "^6.1 || ^7.0",
- "symfony/filesystem": "^6.1 || ^7.0",
- "symfony/finder": "^6.1 || ^7.0",
- "symfony/options-resolver": "^6.1 || ^7.0",
- "symfony/process": "^6.1 || ^7.0",
+ "symfony/console": "^6.1 || ^7.0 || ^8.0",
+ "symfony/filesystem": "^6.1 || ^7.0 || ^8.0",
+ "symfony/finder": "^6.1 || ^7.0 || ^8.0",
+ "symfony/options-resolver": "^6.1 || ^7.0 || ^8.0",
+ "symfony/process": "^6.1 || ^7.0 || ^8.0",
"webmozart/glob": "^4.6"
},
"require-dev": {
"dantleech/invoke": "^2.0",
"ergebnis/composer-normalize": "^2.39",
- "friendsofphp/php-cs-fixer": "^3.0",
"jangregor/phpstan-prophecy": "^1.0",
- "phpspec/prophecy": "dev-master",
+ "php-cs-fixer/shim": "^3.9",
+ "phpspec/prophecy": "^1.22",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^10.4 || ^11.0",
"rector/rector": "^1.2",
- "symfony/error-handler": "^6.1 || ^7.0",
- "symfony/var-dumper": "^6.1 || ^7.0"
+ "symfony/error-handler": "^6.1 || ^7.0 || ^8.0",
+ "symfony/var-dumper": "^6.1 || ^7.0 || ^8.0"
},
"suggest": {
"ext-xdebug": "For Xdebug profiling extension."
@@ -2445,7 +2465,7 @@
],
"support": {
"issues": "https://github.com/phpbench/phpbench/issues",
- "source": "https://github.com/phpbench/phpbench/tree/1.4.1"
+ "source": "https://github.com/phpbench/phpbench/tree/1.4.3"
},
"funding": [
{
@@ -2453,24 +2473,19 @@
"type": "github"
}
],
- "time": "2025-03-12T08:01:40+00:00"
+ "time": "2025-11-06T19:07:31+00:00"
},
{
"name": "phpstan/phpstan",
- "version": "1.12.21",
- "source": {
- "type": "git",
- "url": "https://github.com/phpstan/phpstan.git",
- "reference": "14276fdef70575106a3392a4ed553c06a984df28"
- },
+ "version": "2.1.33",
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/14276fdef70575106a3392a4ed553c06a984df28",
- "reference": "14276fdef70575106a3392a4ed553c06a984df28",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f",
+ "reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f",
"shasum": ""
},
"require": {
- "php": "^7.2|^8.0"
+ "php": "^7.4|^8.0"
},
"conflict": {
"phpstan/phpstan-shim": "*"
@@ -2511,39 +2526,39 @@
"type": "github"
}
],
- "time": "2025-03-09T09:24:50+00:00"
+ "time": "2025-12-05T10:24:31+00:00"
},
{
"name": "phpunit/php-code-coverage",
- "version": "9.2.32",
+ "version": "11.0.11",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
- "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5"
+ "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/85402a822d1ecf1db1096959413d35e1c37cf1a5",
- "reference": "85402a822d1ecf1db1096959413d35e1c37cf1a5",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4",
+ "reference": "4f7722aa9a7b76aa775e2d9d4e95d1ea16eeeef4",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
- "nikic/php-parser": "^4.19.1 || ^5.1.0",
- "php": ">=7.3",
- "phpunit/php-file-iterator": "^3.0.6",
- "phpunit/php-text-template": "^2.0.4",
- "sebastian/code-unit-reverse-lookup": "^2.0.3",
- "sebastian/complexity": "^2.0.3",
- "sebastian/environment": "^5.1.5",
- "sebastian/lines-of-code": "^1.0.4",
- "sebastian/version": "^3.0.2",
+ "nikic/php-parser": "^5.4.0",
+ "php": ">=8.2",
+ "phpunit/php-file-iterator": "^5.1.0",
+ "phpunit/php-text-template": "^4.0.1",
+ "sebastian/code-unit-reverse-lookup": "^4.0.1",
+ "sebastian/complexity": "^4.0.1",
+ "sebastian/environment": "^7.2.0",
+ "sebastian/lines-of-code": "^3.0.1",
+ "sebastian/version": "^5.0.2",
"theseer/tokenizer": "^1.2.3"
},
"require-dev": {
- "phpunit/phpunit": "^9.6"
+ "phpunit/phpunit": "^11.5.2"
},
"suggest": {
"ext-pcov": "PHP extension that provides line coverage",
@@ -2552,7 +2567,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-main": "9.2.x-dev"
+ "dev-main": "11.0.x-dev"
}
},
"autoload": {
@@ -2581,40 +2596,52 @@
"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/9.2.32"
+ "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.11"
},
"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-code-coverage",
+ "type": "tidelift"
}
],
- "time": "2024-08-22T04:23:01+00:00"
+ "time": "2025-08-27T14:37:49+00:00"
},
{
"name": "phpunit/php-file-iterator",
- "version": "3.0.6",
+ "version": "5.1.0",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-file-iterator.git",
- "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf"
+ "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
- "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6",
+ "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -2641,7 +2668,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
- "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6"
+ "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0"
},
"funding": [
{
@@ -2649,28 +2677,28 @@
"type": "github"
}
],
- "time": "2021-12-02T12:48:52+00:00"
+ "time": "2024-08-27T05:02:59+00:00"
},
{
"name": "phpunit/php-invoker",
- "version": "3.1.1",
+ "version": "5.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-invoker.git",
- "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67"
+ "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
- "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2",
+ "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
"ext-pcntl": "*",
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"suggest": {
"ext-pcntl": "*"
@@ -2678,7 +2706,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.1-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -2704,7 +2732,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-invoker/issues",
- "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1"
+ "security": "https://github.com/sebastianbergmann/php-invoker/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1"
},
"funding": [
{
@@ -2712,32 +2741,32 @@
"type": "github"
}
],
- "time": "2020-09-28T05:58:55+00:00"
+ "time": "2024-07-03T05:07:44+00:00"
},
{
"name": "phpunit/php-text-template",
- "version": "2.0.4",
+ "version": "4.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-text-template.git",
- "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28"
+ "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
- "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964",
+ "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -2763,7 +2792,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
- "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4"
+ "security": "https://github.com/sebastianbergmann/php-text-template/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1"
},
"funding": [
{
@@ -2771,32 +2801,32 @@
"type": "github"
}
],
- "time": "2020-10-26T05:33:50+00:00"
+ "time": "2024-07-03T05:08:43+00:00"
},
{
"name": "phpunit/php-timer",
- "version": "5.0.3",
+ "version": "7.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-timer.git",
- "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2"
+ "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
- "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2",
+ "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3",
+ "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -2822,7 +2852,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
- "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3"
+ "security": "https://github.com/sebastianbergmann/php-timer/security/policy",
+ "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1"
},
"funding": [
{
@@ -2830,54 +2861,52 @@
"type": "github"
}
],
- "time": "2020-10-26T13:16:10+00:00"
+ "time": "2024-07-03T05:09:35+00:00"
},
{
"name": "phpunit/phpunit",
- "version": "9.6.22",
+ "version": "11.5.46",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c"
+ "reference": "75dfe79a2aa30085b7132bb84377c24062193f33"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
- "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/75dfe79a2aa30085b7132bb84377c24062193f33",
+ "reference": "75dfe79a2aa30085b7132bb84377c24062193f33",
"shasum": ""
},
"require": {
- "doctrine/instantiator": "^1.5.0 || ^2",
"ext-dom": "*",
"ext-json": "*",
"ext-libxml": "*",
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.12.1",
+ "myclabs/deep-copy": "^1.13.4",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
- "php": ">=7.3",
- "phpunit/php-code-coverage": "^9.2.32",
- "phpunit/php-file-iterator": "^3.0.6",
- "phpunit/php-invoker": "^3.1.1",
- "phpunit/php-text-template": "^2.0.4",
- "phpunit/php-timer": "^5.0.3",
- "sebastian/cli-parser": "^1.0.2",
- "sebastian/code-unit": "^1.0.8",
- "sebastian/comparator": "^4.0.8",
- "sebastian/diff": "^4.0.6",
- "sebastian/environment": "^5.1.5",
- "sebastian/exporter": "^4.0.6",
- "sebastian/global-state": "^5.0.7",
- "sebastian/object-enumerator": "^4.0.4",
- "sebastian/resource-operations": "^3.0.4",
- "sebastian/type": "^3.2.1",
- "sebastian/version": "^3.0.2"
+ "php": ">=8.2",
+ "phpunit/php-code-coverage": "^11.0.11",
+ "phpunit/php-file-iterator": "^5.1.0",
+ "phpunit/php-invoker": "^5.0.1",
+ "phpunit/php-text-template": "^4.0.1",
+ "phpunit/php-timer": "^7.0.1",
+ "sebastian/cli-parser": "^3.0.2",
+ "sebastian/code-unit": "^3.0.3",
+ "sebastian/comparator": "^6.3.2",
+ "sebastian/diff": "^6.0.2",
+ "sebastian/environment": "^7.2.1",
+ "sebastian/exporter": "^6.3.2",
+ "sebastian/global-state": "^7.0.2",
+ "sebastian/object-enumerator": "^6.0.1",
+ "sebastian/type": "^5.1.3",
+ "sebastian/version": "^5.0.2",
+ "staabm/side-effects-detector": "^1.0.5"
},
"suggest": {
- "ext-soap": "To be able to generate mocks based on WSDL files",
- "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage"
+ "ext-soap": "To be able to generate mocks based on WSDL files"
},
"bin": [
"phpunit"
@@ -2885,7 +2914,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "9.6-dev"
+ "dev-main": "11.5-dev"
}
},
"autoload": {
@@ -2917,7 +2946,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.46"
},
"funding": [
{
@@ -2928,12 +2957,20 @@
"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/phpunit",
"type": "tidelift"
}
],
- "time": "2024-12-05T13:48:26+00:00"
+ "time": "2025-12-06T08:01:15+00:00"
},
{
"name": "psr/cache",
@@ -2986,28 +3023,28 @@
},
{
"name": "sebastian/cli-parser",
- "version": "1.0.2",
+ "version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/cli-parser.git",
- "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b"
+ "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
- "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b",
+ "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180",
+ "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-main": "3.0-dev"
}
},
"autoload": {
@@ -3030,7 +3067,8 @@
"homepage": "https://github.com/sebastianbergmann/cli-parser",
"support": {
"issues": "https://github.com/sebastianbergmann/cli-parser/issues",
- "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2"
+ "security": "https://github.com/sebastianbergmann/cli-parser/security/policy",
+ "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2"
},
"funding": [
{
@@ -3038,32 +3076,32 @@
"type": "github"
}
],
- "time": "2024-03-02T06:27:43+00:00"
+ "time": "2024-07-03T04:41:36+00:00"
},
{
"name": "sebastian/code-unit",
- "version": "1.0.8",
+ "version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/code-unit.git",
- "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120"
+ "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120",
- "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64",
+ "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-main": "3.0-dev"
}
},
"autoload": {
@@ -3086,7 +3124,8 @@
"homepage": "https://github.com/sebastianbergmann/code-unit",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit/issues",
- "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8"
+ "security": "https://github.com/sebastianbergmann/code-unit/security/policy",
+ "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3"
},
"funding": [
{
@@ -3094,32 +3133,32 @@
"type": "github"
}
],
- "time": "2020-10-26T13:08:54+00:00"
+ "time": "2025-03-19T07:56:08+00:00"
},
{
"name": "sebastian/code-unit-reverse-lookup",
- "version": "2.0.3",
+ "version": "4.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git",
- "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5"
+ "reference": "183a9b2632194febd219bb9246eee421dad8d45e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
- "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5",
+ "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e",
+ "reference": "183a9b2632194febd219bb9246eee421dad8d45e",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -3141,7 +3180,8 @@
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
- "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3"
+ "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy",
+ "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1"
},
"funding": [
{
@@ -3149,34 +3189,39 @@
"type": "github"
}
],
- "time": "2020-09-28T05:30:19+00:00"
+ "time": "2024-07-03T04:45:54+00:00"
},
{
"name": "sebastian/comparator",
- "version": "4.0.8",
+ "version": "6.3.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
- "reference": "fa0f136dd2334583309d32b62544682ee972b51a"
+ "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a",
- "reference": "fa0f136dd2334583309d32b62544682ee972b51a",
+ "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/85c77556683e6eee4323e4c5468641ca0237e2e8",
+ "reference": "85c77556683e6eee4323e4c5468641ca0237e2e8",
"shasum": ""
},
"require": {
- "php": ">=7.3",
- "sebastian/diff": "^4.0",
- "sebastian/exporter": "^4.0"
+ "ext-dom": "*",
+ "ext-mbstring": "*",
+ "php": ">=8.2",
+ "sebastian/diff": "^6.0",
+ "sebastian/exporter": "^6.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.4"
+ },
+ "suggest": {
+ "ext-bcmath": "For comparing BcMath\\Number objects"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "6.3-dev"
}
},
"autoload": {
@@ -3215,41 +3260,54 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
- "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8"
+ "security": "https://github.com/sebastianbergmann/comparator/security/policy",
+ "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.2"
},
"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/sebastian/comparator",
+ "type": "tidelift"
}
],
- "time": "2022-09-14T12:41:17+00:00"
+ "time": "2025-08-10T08:07:46+00:00"
},
{
"name": "sebastian/complexity",
- "version": "2.0.3",
+ "version": "4.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/complexity.git",
- "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
+ "reference": "ee41d384ab1906c68852636b6de493846e13e5a0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
- "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
+ "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0",
+ "reference": "ee41d384ab1906c68852636b6de493846e13e5a0",
"shasum": ""
},
"require": {
- "nikic/php-parser": "^4.18 || ^5.0",
- "php": ">=7.3"
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -3272,7 +3330,8 @@
"homepage": "https://github.com/sebastianbergmann/complexity",
"support": {
"issues": "https://github.com/sebastianbergmann/complexity/issues",
- "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
+ "security": "https://github.com/sebastianbergmann/complexity/security/policy",
+ "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1"
},
"funding": [
{
@@ -3280,33 +3339,33 @@
"type": "github"
}
],
- "time": "2023-12-22T06:19:30+00:00"
+ "time": "2024-07-03T04:49:50+00:00"
},
{
"name": "sebastian/diff",
- "version": "4.0.6",
+ "version": "6.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/diff.git",
- "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc"
+ "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc",
- "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc",
+ "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544",
+ "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3",
+ "phpunit/phpunit": "^11.0",
"symfony/process": "^4.2 || ^5"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -3338,7 +3397,8 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
- "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6"
+ "security": "https://github.com/sebastianbergmann/diff/security/policy",
+ "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2"
},
"funding": [
{
@@ -3346,27 +3406,27 @@
"type": "github"
}
],
- "time": "2024-03-02T06:30:58+00:00"
+ "time": "2024-07-03T04:53:05+00:00"
},
{
"name": "sebastian/environment",
- "version": "5.1.5",
+ "version": "7.2.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/environment.git",
- "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed"
+ "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
- "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed",
+ "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4",
+ "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.3"
},
"suggest": {
"ext-posix": "*"
@@ -3374,7 +3434,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.1-dev"
+ "dev-main": "7.2-dev"
}
},
"autoload": {
@@ -3393,7 +3453,7 @@
}
],
"description": "Provides functionality to handle HHVM/PHP environments",
- "homepage": "http://www.github.com/sebastianbergmann/environment",
+ "homepage": "https://github.com/sebastianbergmann/environment",
"keywords": [
"Xdebug",
"environment",
@@ -3401,42 +3461,55 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
- "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5"
+ "security": "https://github.com/sebastianbergmann/environment/security/policy",
+ "source": "https://github.com/sebastianbergmann/environment/tree/7.2.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/sebastian/environment",
+ "type": "tidelift"
}
],
- "time": "2023-02-03T06:03:51+00:00"
+ "time": "2025-05-21T11:55:47+00:00"
},
{
"name": "sebastian/exporter",
- "version": "4.0.6",
+ "version": "6.3.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/exporter.git",
- "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72"
+ "reference": "70a298763b40b213ec087c51c739efcaa90bcd74"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72",
- "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72",
+ "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/70a298763b40b213ec087c51c739efcaa90bcd74",
+ "reference": "70a298763b40b213ec087c51c739efcaa90bcd74",
"shasum": ""
},
"require": {
- "php": ">=7.3",
- "sebastian/recursion-context": "^4.0"
+ "ext-mbstring": "*",
+ "php": ">=8.2",
+ "sebastian/recursion-context": "^6.0"
},
"require-dev": {
- "ext-mbstring": "*",
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "6.3-dev"
}
},
"autoload": {
@@ -3478,46 +3551,56 @@
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
- "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6"
+ "security": "https://github.com/sebastianbergmann/exporter/security/policy",
+ "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.2"
},
"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/sebastian/exporter",
+ "type": "tidelift"
}
],
- "time": "2024-03-02T06:33:00+00:00"
+ "time": "2025-09-24T06:12:51+00:00"
},
{
"name": "sebastian/global-state",
- "version": "5.0.7",
+ "version": "7.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/global-state.git",
- "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9"
+ "reference": "3be331570a721f9a4b5917f4209773de17f747d7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
- "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9",
+ "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7",
+ "reference": "3be331570a721f9a4b5917f4209773de17f747d7",
"shasum": ""
},
"require": {
- "php": ">=7.3",
- "sebastian/object-reflector": "^2.0",
- "sebastian/recursion-context": "^4.0"
+ "php": ">=8.2",
+ "sebastian/object-reflector": "^4.0",
+ "sebastian/recursion-context": "^6.0"
},
"require-dev": {
"ext-dom": "*",
- "phpunit/phpunit": "^9.3"
- },
- "suggest": {
- "ext-uopz": "*"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "5.0-dev"
+ "dev-main": "7.0-dev"
}
},
"autoload": {
@@ -3536,13 +3619,14 @@
}
],
"description": "Snapshotting of global state",
- "homepage": "http://www.github.com/sebastianbergmann/global-state",
+ "homepage": "https://www.github.com/sebastianbergmann/global-state",
"keywords": [
"global state"
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
- "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7"
+ "security": "https://github.com/sebastianbergmann/global-state/security/policy",
+ "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2"
},
"funding": [
{
@@ -3550,33 +3634,33 @@
"type": "github"
}
],
- "time": "2024-03-02T06:35:11+00:00"
+ "time": "2024-07-03T04:57:36+00:00"
},
{
"name": "sebastian/lines-of-code",
- "version": "1.0.4",
+ "version": "3.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
- "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
+ "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
- "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
+ "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a",
+ "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a",
"shasum": ""
},
"require": {
- "nikic/php-parser": "^4.18 || ^5.0",
- "php": ">=7.3"
+ "nikic/php-parser": "^5.0",
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "1.0-dev"
+ "dev-main": "3.0-dev"
}
},
"autoload": {
@@ -3599,7 +3683,8 @@
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
"support": {
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
- "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
+ "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy",
+ "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1"
},
"funding": [
{
@@ -3607,34 +3692,34 @@
"type": "github"
}
],
- "time": "2023-12-22T06:20:34+00:00"
+ "time": "2024-07-03T04:58:38+00:00"
},
{
"name": "sebastian/object-enumerator",
- "version": "4.0.4",
+ "version": "6.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-enumerator.git",
- "reference": "5c9eeac41b290a3712d88851518825ad78f45c71"
+ "reference": "f5b498e631a74204185071eb41f33f38d64608aa"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71",
- "reference": "5c9eeac41b290a3712d88851518825ad78f45c71",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa",
+ "reference": "f5b498e631a74204185071eb41f33f38d64608aa",
"shasum": ""
},
"require": {
- "php": ">=7.3",
- "sebastian/object-reflector": "^2.0",
- "sebastian/recursion-context": "^4.0"
+ "php": ">=8.2",
+ "sebastian/object-reflector": "^4.0",
+ "sebastian/recursion-context": "^6.0"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -3656,7 +3741,8 @@
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
- "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4"
+ "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1"
},
"funding": [
{
@@ -3664,32 +3750,32 @@
"type": "github"
}
],
- "time": "2020-10-26T13:12:34+00:00"
+ "time": "2024-07-03T05:00:13+00:00"
},
{
"name": "sebastian/object-reflector",
- "version": "2.0.4",
+ "version": "4.0.1",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/object-reflector.git",
- "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7"
+ "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
- "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7",
+ "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9",
+ "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.0"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "2.0-dev"
+ "dev-main": "4.0-dev"
}
},
"autoload": {
@@ -3711,7 +3797,8 @@
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
- "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4"
+ "security": "https://github.com/sebastianbergmann/object-reflector/security/policy",
+ "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1"
},
"funding": [
{
@@ -3719,32 +3806,32 @@
"type": "github"
}
],
- "time": "2020-10-26T13:14:26+00:00"
+ "time": "2024-07-03T05:01:32+00:00"
},
{
"name": "sebastian/recursion-context",
- "version": "4.0.5",
+ "version": "6.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/recursion-context.git",
- "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1"
+ "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
- "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1",
+ "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/f6458abbf32a6c8174f8f26261475dc133b3d9dc",
+ "reference": "f6458abbf32a6c8174f8f26261475dc133b3d9dc",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.3"
+ "phpunit/phpunit": "^11.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "4.0-dev"
+ "dev-main": "6.0-dev"
}
},
"autoload": {
@@ -3774,94 +3861,53 @@
"homepage": "https://github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
- "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5"
+ "security": "https://github.com/sebastianbergmann/recursion-context/security/policy",
+ "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.3"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
"type": "github"
- }
- ],
- "time": "2023-02-03T06:07:39+00:00"
- },
- {
- "name": "sebastian/resource-operations",
- "version": "3.0.4",
- "source": {
- "type": "git",
- "url": "https://github.com/sebastianbergmann/resource-operations.git",
- "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
- "reference": "05d5692a7993ecccd56a03e40cd7e5b09b1d404e",
- "shasum": ""
- },
- "require": {
- "php": ">=7.3"
- },
- "require-dev": {
- "phpunit/phpunit": "^9.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "3.0-dev"
- }
- },
- "autoload": {
- "classmap": [
- "src/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "BSD-3-Clause"
- ],
- "authors": [
+ },
{
- "name": "Sebastian Bergmann",
- "email": "sebastian@phpunit.de"
- }
- ],
- "description": "Provides a list of PHP built-in functions that operate on resources",
- "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
- "support": {
- "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.4"
- },
- "funding": [
+ "url": "https://liberapay.com/sebastianbergmann",
+ "type": "liberapay"
+ },
{
- "url": "https://github.com/sebastianbergmann",
- "type": "github"
+ "url": "https://thanks.dev/u/gh/sebastianbergmann",
+ "type": "thanks_dev"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context",
+ "type": "tidelift"
}
],
- "time": "2024-03-14T16:00:52+00:00"
+ "time": "2025-08-13T04:42:22+00:00"
},
{
"name": "sebastian/type",
- "version": "3.2.1",
+ "version": "5.1.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/type.git",
- "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7"
+ "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
- "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7",
+ "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/f77d2d4e78738c98d9a68d2596fe5e8fa380f449",
+ "reference": "f77d2d4e78738c98d9a68d2596fe5e8fa380f449",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"require-dev": {
- "phpunit/phpunit": "^9.5"
+ "phpunit/phpunit": "^11.3"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.2-dev"
+ "dev-main": "5.1-dev"
}
},
"autoload": {
@@ -3884,37 +3930,50 @@
"homepage": "https://github.com/sebastianbergmann/type",
"support": {
"issues": "https://github.com/sebastianbergmann/type/issues",
- "source": "https://github.com/sebastianbergmann/type/tree/3.2.1"
+ "security": "https://github.com/sebastianbergmann/type/security/policy",
+ "source": "https://github.com/sebastianbergmann/type/tree/5.1.3"
},
"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/sebastian/type",
+ "type": "tidelift"
}
],
- "time": "2023-02-03T06:13:03+00:00"
+ "time": "2025-08-09T06:55:48+00:00"
},
{
"name": "sebastian/version",
- "version": "3.0.2",
+ "version": "5.0.2",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/version.git",
- "reference": "c6c1022351a901512170118436c764e473f6de8c"
+ "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c",
- "reference": "c6c1022351a901512170118436c764e473f6de8c",
+ "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874",
+ "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874",
"shasum": ""
},
"require": {
- "php": ">=7.3"
+ "php": ">=8.2"
},
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "3.0-dev"
+ "dev-main": "5.0-dev"
}
},
"autoload": {
@@ -3937,7 +3996,8 @@
"homepage": "https://github.com/sebastianbergmann/version",
"support": {
"issues": "https://github.com/sebastianbergmann/version/issues",
- "source": "https://github.com/sebastianbergmann/version/tree/3.0.2"
+ "security": "https://github.com/sebastianbergmann/version/security/policy",
+ "source": "https://github.com/sebastianbergmann/version/tree/5.0.2"
},
"funding": [
{
@@ -3945,7 +4005,7 @@
"type": "github"
}
],
- "time": "2020-09-28T06:39:44+00:00"
+ "time": "2024-10-09T05:16:32+00:00"
},
{
"name": "seld/jsonlint",
@@ -4011,48 +4071,125 @@
],
"time": "2024-07-11T14:55:45+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",
+ "phpstan/phpstan": "^1.12.6",
+ "phpunit/phpunit": "^9.6.21",
+ "symfony/var-dumper": "^5.4.43",
+ "tomasvotruba/type-coverage": "1.0.0",
+ "tomasvotruba/unused-public": "1.0.0"
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "lib/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "A static analysis tool to detect side effects in PHP code",
+ "keywords": [
+ "static analysis"
+ ],
+ "support": {
+ "issues": "https://github.com/staabm/side-effects-detector/issues",
+ "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/staabm",
+ "type": "github"
+ }
+ ],
+ "time": "2024-10-20T05:08:20+00:00"
+ },
+ {
+ "name": "swoole/ide-helper",
+ "version": "6.0.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/swoole/ide-helper.git",
+ "reference": "6f12243dce071714c5febe059578d909698f9a52"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/swoole/ide-helper/zipball/6f12243dce071714c5febe059578d909698f9a52",
+ "reference": "6f12243dce071714c5febe059578d909698f9a52",
+ "shasum": ""
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Team Swoole",
+ "email": "team@swoole.com"
+ }
+ ],
+ "description": "IDE help files for Swoole.",
+ "support": {
+ "issues": "https://github.com/swoole/ide-helper/issues",
+ "source": "https://github.com/swoole/ide-helper/tree/6.0.2"
+ },
+ "time": "2025-03-23T07:31:41+00:00"
+ },
{
"name": "symfony/console",
- "version": "v7.2.1",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
- "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3"
+ "reference": "fcb73f69d655b48fcb894a262f074218df08bd58"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
- "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3",
+ "url": "https://api.github.com/repos/symfony/console/zipball/fcb73f69d655b48fcb894a262f074218df08bd58",
+ "reference": "fcb73f69d655b48fcb894a262f074218df08bd58",
"shasum": ""
},
"require": {
- "php": ">=8.2",
- "symfony/polyfill-mbstring": "~1.0",
+ "php": ">=8.4",
+ "symfony/polyfill-mbstring": "^1.0",
"symfony/service-contracts": "^2.5|^3",
- "symfony/string": "^6.4|^7.0"
- },
- "conflict": {
- "symfony/dependency-injection": "<6.4",
- "symfony/dotenv": "<6.4",
- "symfony/event-dispatcher": "<6.4",
- "symfony/lock": "<6.4",
- "symfony/process": "<6.4"
+ "symfony/string": "^7.4|^8.0"
},
"provide": {
"psr/log-implementation": "1.0|2.0|3.0"
},
"require-dev": {
"psr/log": "^1|^2|^3",
- "symfony/config": "^6.4|^7.0",
- "symfony/dependency-injection": "^6.4|^7.0",
- "symfony/event-dispatcher": "^6.4|^7.0",
- "symfony/http-foundation": "^6.4|^7.0",
- "symfony/http-kernel": "^6.4|^7.0",
- "symfony/lock": "^6.4|^7.0",
- "symfony/messenger": "^6.4|^7.0",
- "symfony/process": "^6.4|^7.0",
- "symfony/stopwatch": "^6.4|^7.0",
- "symfony/var-dumper": "^6.4|^7.0"
+ "symfony/config": "^7.4|^8.0",
+ "symfony/dependency-injection": "^7.4|^8.0",
+ "symfony/event-dispatcher": "^7.4|^8.0",
+ "symfony/http-foundation": "^7.4|^8.0",
+ "symfony/http-kernel": "^7.4|^8.0",
+ "symfony/lock": "^7.4|^8.0",
+ "symfony/messenger": "^7.4|^8.0",
+ "symfony/process": "^7.4|^8.0",
+ "symfony/stopwatch": "^7.4|^8.0",
+ "symfony/var-dumper": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -4086,7 +4223,7 @@
"terminal"
],
"support": {
- "source": "https://github.com/symfony/console/tree/v7.2.1"
+ "source": "https://github.com/symfony/console/tree/v8.0.1"
},
"funding": [
{
@@ -4097,34 +4234,38 @@
"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-11T03:49:26+00:00"
+ "time": "2025-12-05T15:25:33+00:00"
},
{
"name": "symfony/filesystem",
- "version": "v7.2.0",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
- "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb"
+ "reference": "d937d400b980523dc9ee946bb69972b5e619058d"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
- "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
+ "reference": "d937d400b980523dc9ee946bb69972b5e619058d",
"shasum": ""
},
"require": {
- "php": ">=8.2",
+ "php": ">=8.4",
"symfony/polyfill-ctype": "~1.8",
"symfony/polyfill-mbstring": "~1.8"
},
"require-dev": {
- "symfony/process": "^6.4|^7.0"
+ "symfony/process": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -4152,7 +4293,7 @@
"description": "Provides basic utilities for the filesystem",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/filesystem/tree/v7.2.0"
+ "source": "https://github.com/symfony/filesystem/tree/v8.0.1"
},
"funding": [
{
@@ -4163,32 +4304,36 @@
"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-10-25T15:15:23+00:00"
+ "time": "2025-12-01T09:13:36+00:00"
},
{
"name": "symfony/finder",
- "version": "v7.2.2",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
- "reference": "87a71856f2f56e4100373e92529eed3171695cfb"
+ "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb",
- "reference": "87a71856f2f56e4100373e92529eed3171695cfb",
+ "url": "https://api.github.com/repos/symfony/finder/zipball/7598dd5770580fa3517ec83e8da0c9b9e01f4291",
+ "reference": "7598dd5770580fa3517ec83e8da0c9b9e01f4291",
"shasum": ""
},
"require": {
- "php": ">=8.2"
+ "php": ">=8.4"
},
"require-dev": {
- "symfony/filesystem": "^6.4|^7.0"
+ "symfony/filesystem": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -4216,7 +4361,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/finder/tree/v7.2.2"
+ "source": "https://github.com/symfony/finder/tree/v8.0.0"
},
"funding": [
{
@@ -4227,29 +4372,33 @@
"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-30T19:00:17+00:00"
+ "time": "2025-11-05T14:36:47+00:00"
},
{
"name": "symfony/options-resolver",
- "version": "v7.2.0",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
- "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50"
+ "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50",
- "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d2b592535ffa6600c265a3893a7f7fd2bad82dd7",
+ "reference": "d2b592535ffa6600c265a3893a7f7fd2bad82dd7",
"shasum": ""
},
"require": {
- "php": ">=8.2",
+ "php": ">=8.4",
"symfony/deprecation-contracts": "^2.5|^3"
},
"type": "library",
@@ -4283,7 +4432,7 @@
"options"
],
"support": {
- "source": "https://github.com/symfony/options-resolver/tree/v7.2.0"
+ "source": "https://github.com/symfony/options-resolver/tree/v8.0.0"
},
"funding": [
{
@@ -4294,16 +4443,20 @@
"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-11-20T11:17:29+00:00"
+ "time": "2025-11-12T15:55:31+00:00"
},
{
"name": "symfony/polyfill-ctype",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
@@ -4362,7 +4515,7 @@
"portable"
],
"support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0"
},
"funding": [
{
@@ -4373,6 +4526,10 @@
"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"
@@ -4382,16 +4539,16 @@
},
{
"name": "symfony/polyfill-intl-grapheme",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
+ "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70",
+ "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70",
"shasum": ""
},
"require": {
@@ -4440,7 +4597,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0"
},
"funding": [
{
@@ -4451,16 +4608,20 @@
"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"
+ "time": "2025-06-27T09:58:17+00:00"
},
{
"name": "symfony/polyfill-intl-normalizer",
- "version": "v1.31.0",
+ "version": "v1.33.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-intl-normalizer.git",
@@ -4521,7 +4682,7 @@
"shim"
],
"support": {
- "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0"
+ "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0"
},
"funding": [
{
@@ -4532,6 +4693,10 @@
"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"
@@ -4541,20 +4706,20 @@
},
{
"name": "symfony/process",
- "version": "v7.2.4",
+ "version": "v8.0.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
- "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf"
+ "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
- "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf",
+ "url": "https://api.github.com/repos/symfony/process/zipball/a0a750500c4ce900d69ba4e9faf16f82c10ee149",
+ "reference": "a0a750500c4ce900d69ba4e9faf16f82c10ee149",
"shasum": ""
},
"require": {
- "php": ">=8.2"
+ "php": ">=8.4"
},
"type": "library",
"autoload": {
@@ -4582,7 +4747,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/process/tree/v7.2.4"
+ "source": "https://github.com/symfony/process/tree/v8.0.0"
},
"funding": [
{
@@ -4593,44 +4758,47 @@
"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-02-05T08:33:46+00:00"
+ "time": "2025-10-16T16:25:44+00:00"
},
{
"name": "symfony/string",
- "version": "v7.2.0",
+ "version": "v8.0.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
- "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82"
+ "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82",
- "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82",
+ "url": "https://api.github.com/repos/symfony/string/zipball/ba65a969ac918ce0cc3edfac6cdde847eba231dc",
+ "reference": "ba65a969ac918ce0cc3edfac6cdde847eba231dc",
"shasum": ""
},
"require": {
- "php": ">=8.2",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-intl-grapheme": "~1.0",
- "symfony/polyfill-intl-normalizer": "~1.0",
- "symfony/polyfill-mbstring": "~1.0"
+ "php": ">=8.4",
+ "symfony/polyfill-ctype": "^1.8",
+ "symfony/polyfill-intl-grapheme": "^1.33",
+ "symfony/polyfill-intl-normalizer": "^1.0",
+ "symfony/polyfill-mbstring": "^1.0"
},
"conflict": {
"symfony/translation-contracts": "<2.5"
},
"require-dev": {
- "symfony/emoji": "^7.1",
- "symfony/error-handler": "^6.4|^7.0",
- "symfony/http-client": "^6.4|^7.0",
- "symfony/intl": "^6.4|^7.0",
+ "symfony/emoji": "^7.4|^8.0",
+ "symfony/http-client": "^7.4|^8.0",
+ "symfony/intl": "^7.4|^8.0",
"symfony/translation-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^6.4|^7.0"
+ "symfony/var-exporter": "^7.4|^8.0"
},
"type": "library",
"autoload": {
@@ -4669,7 +4837,7 @@
"utf8"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v7.2.0"
+ "source": "https://github.com/symfony/string/tree/v8.0.1"
},
"funding": [
{
@@ -4680,25 +4848,29 @@
"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-11-13T13:31:26+00:00"
+ "time": "2025-12-01T09:13:36+00:00"
},
{
"name": "theseer/tokenizer",
- "version": "1.2.3",
+ "version": "1.3.1",
"source": {
"type": "git",
"url": "https://github.com/theseer/tokenizer.git",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2"
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
- "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2",
+ "url": "https://api.github.com/repos/theseer/tokenizer/zipball/b7489ce515e168639d17feec34b8847c326b0b3c",
+ "reference": "b7489ce515e168639d17feec34b8847c326b0b3c",
"shasum": ""
},
"require": {
@@ -4727,7 +4899,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/1.3.1"
},
"funding": [
{
@@ -4735,7 +4907,7 @@
"type": "github"
}
],
- "time": "2024-03-03T12:36:25+00:00"
+ "time": "2025-11-17T20:03:58+00:00"
},
{
"name": "webmozart/glob",
@@ -4789,7 +4961,7 @@
],
"aliases": [],
"minimum-stability": "stable",
- "stability-flags": [],
+ "stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
@@ -4797,6 +4969,6 @@
"ext-opentelemetry": "*",
"php": ">=8.0"
},
- "platform-dev": [],
- "plugin-api-version": "2.6.0"
+ "platform-dev": {},
+ "plugin-api-version": "2.9.0"
}
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..fedcb8a
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,36 @@
+services:
+ # OTLP Collector for integration testing
+ otel-collector:
+ image: otel/opentelemetry-collector:latest
+ container_name: telemetry-otel-collector
+ command: ["--config=/etc/otel/config.yaml"]
+ volumes:
+ - ./docker/otel-collector-config.yaml:/etc/otel/config.yaml:ro
+ ports:
+ - "4317:4317" # gRPC
+ - "4318:4318" # HTTP
+ networks:
+ - telemetry
+
+ tests:
+ build:
+ context: .
+ dockerfile: docker/Dockerfile
+ args:
+ PHP_VERSION: ${PHP_VERSION:-8.4}
+ volumes:
+ - .:/app
+ - composer-cache:/root/.composer/cache
+ working_dir: /app
+ depends_on:
+ - otel-collector
+ environment:
+ - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
+ networks:
+ - telemetry
+
+networks:
+ telemetry:
+
+volumes:
+ composer-cache:
diff --git a/docker/Dockerfile b/docker/Dockerfile
new file mode 100644
index 0000000..6c9c050
--- /dev/null
+++ b/docker/Dockerfile
@@ -0,0 +1,25 @@
+ARG PHP_VERSION=8.4
+FROM php:${PHP_VERSION}-cli-alpine
+
+RUN apk add --no-cache \
+ git \
+ unzip \
+ openssl-dev \
+ curl-dev \
+ protobuf-dev \
+ linux-headers \
+ $PHPIZE_DEPS
+
+RUN pecl install opentelemetry protobuf swoole && \
+ docker-php-ext-enable opentelemetry protobuf swoole
+
+RUN docker-php-ext-install sockets
+
+COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
+
+WORKDIR /app
+
+COPY composer.json composer.lock ./
+RUN composer install --no-scripts --no-autoloader --prefer-dist --ignore-platform-reqs
+COPY . .
+CMD ["tail", "-f", "/dev/null"]
diff --git a/docker/otel-collector-config.yaml b/docker/otel-collector-config.yaml
new file mode 100644
index 0000000..3c08894
--- /dev/null
+++ b/docker/otel-collector-config.yaml
@@ -0,0 +1,31 @@
+receivers:
+ otlp:
+ protocols:
+ grpc:
+ endpoint: 0.0.0.0:4317
+ http:
+ endpoint: 0.0.0.0:4318
+
+processors:
+ batch:
+ timeout: 1s
+ send_batch_size: 1024
+
+exporters:
+ debug:
+ verbosity: detailed
+
+service:
+ pipelines:
+ metrics:
+ receivers: [otlp]
+ processors: [batch]
+ exporters: [debug]
+ traces:
+ receivers: [otlp]
+ processors: [batch]
+ exporters: [debug]
+ logs:
+ receivers: [otlp]
+ processors: [batch]
+ exporters: [debug]
diff --git a/phpstan.neon b/phpstan.neon
index 8886f7f..00c5561 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,4 +1,4 @@
parameters:
- level: 5
+ level: max
paths:
- src
\ No newline at end of file
diff --git a/phpunit.xml b/phpunit.xml
index de6deb0..af6752f 100755
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,17 +1,18 @@
+ cacheDirectory=".phpunit.cache"
+>
-
- ./tests/e2e/Client.php
- ./tests/
+
+ ./tests
+
+
+ ./src
+
+
\ No newline at end of file
diff --git a/src/Telemetry/Adapter.php b/src/Telemetry/Adapter.php
index 7c3048f..616c45e 100644
--- a/src/Telemetry/Adapter.php
+++ b/src/Telemetry/Adapter.php
@@ -4,6 +4,9 @@
interface Adapter
{
+ /**
+ * @param array $advisory
+ */
public function createCounter(
string $name,
?string $unit = null,
@@ -11,6 +14,9 @@ public function createCounter(
array $advisory = [],
): Counter;
+ /**
+ * @param array $advisory
+ */
public function createHistogram(
string $name,
?string $unit = null,
@@ -18,6 +24,9 @@ public function createHistogram(
array $advisory = [],
): Histogram;
+ /**
+ * @param array $advisory
+ */
public function createGauge(
string $name,
?string $unit = null,
@@ -25,6 +34,9 @@ public function createGauge(
array $advisory = [],
): Gauge;
+ /**
+ * @param array $advisory
+ */
public function createUpDownCounter(
string $name,
?string $unit = null,
diff --git a/src/Telemetry/Adapter/None.php b/src/Telemetry/Adapter/None.php
index 495a8f5..cb1285b 100644
--- a/src/Telemetry/Adapter/None.php
+++ b/src/Telemetry/Adapter/None.php
@@ -10,36 +10,60 @@
class None implements Adapter
{
+ /**
+ * @param array $advisory
+ */
public function createCounter(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Counter
{
return new class () extends Counter {
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
public function add(float|int $amount, iterable $attributes = []): void
{
}
};
}
+ /**
+ * @param array $advisory
+ */
public function createHistogram(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Histogram
{
return new class () extends Histogram {
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
public function record(float|int $amount, iterable $attributes = []): void
{
}
};
}
+ /**
+ * @param array $advisory
+ */
public function createGauge(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Gauge
{
return new class () extends Gauge {
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
public function record(float|int $amount, iterable $attributes = []): void
{
}
};
}
+ /**
+ * @param array $advisory
+ */
public function createUpDownCounter(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): UpDownCounter
{
return new class () extends UpDownCounter {
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
public function add(float|int $amount, iterable $attributes = []): void
{
}
diff --git a/src/Telemetry/Adapter/OpenTelemetry.php b/src/Telemetry/Adapter/OpenTelemetry.php
index 0405f7d..b2ff293 100644
--- a/src/Telemetry/Adapter/OpenTelemetry.php
+++ b/src/Telemetry/Adapter/OpenTelemetry.php
@@ -12,6 +12,7 @@
use OpenTelemetry\Contrib\Otlp\OtlpHttpTransportFactory;
use OpenTelemetry\SDK\Common\Attribute\Attributes;
use OpenTelemetry\SDK\Common\Attribute\AttributesInterface;
+use OpenTelemetry\SDK\Common\Export\TransportInterface;
use OpenTelemetry\SDK\Metrics\Data\Temporality;
use OpenTelemetry\SDK\Metrics\MeterProvider;
use OpenTelemetry\SDK\Metrics\MetricExporterInterface;
@@ -29,7 +30,12 @@
class OpenTelemetry implements Adapter
{
private MetricReaderInterface $reader;
+
private MeterInterface $meter;
+
+ /**
+ * @var array>
+ */
private array $meterStorage = [
Counter::class => [],
UpDownCounter::class => [],
@@ -37,17 +43,41 @@ class OpenTelemetry implements Adapter
Gauge::class => [],
];
- public function __construct(string $endpoint, string $serviceNamespace, string $serviceName, string $serviceInstanceId)
- {
- $exporter = $this->createExporter($endpoint);
+ /**
+ * @param string $endpoint
+ * @param string $serviceNamespace
+ * @param string $serviceName
+ * @param string $serviceInstanceId
+ * @param TransportInterface|null $transport
+ */
+ public function __construct(
+ string $endpoint,
+ string $serviceNamespace,
+ string $serviceName,
+ string $serviceInstanceId,
+ protected ?TransportInterface $transport = null
+ ) {
+ if ($this->transport === null) {
+ $this->transport = (new OtlpHttpTransportFactory())
+ ->create($endpoint, ContentTypes::PROTOBUF);
+ }
+
+ $exporter = $this->createExporter($this->transport);
+
$attributes = Attributes::create([
'service.namespace' => $serviceNamespace,
'service.name' => $serviceName,
'service.instance.id' => $serviceInstanceId,
]);
+
$this->meter = $this->initMeter($exporter, $attributes);
}
+ /**
+ * Initialize Meter
+ *
+ * @param AttributesInterface $attributes
+ */
protected function initMeter(MetricExporterInterface $exporter, AttributesInterface $attributes): MeterInterface
{
$this->reader = new ExportingReader($exporter);
@@ -61,77 +91,140 @@ protected function initMeter(MetricExporterInterface $exporter, AttributesInterf
return $meterProvider->getMeter('cloud');
}
- protected function createExporter(string $endpoint): MetricExporterInterface
+ /**
+ * Create Metric Exporter
+ *
+ * @param TransportInterface $transport
+ */
+ protected function createExporter(TransportInterface $transport): MetricExporterInterface
{
- $transport = (new OtlpHttpTransportFactory())->create($endpoint, ContentTypes::PROTOBUF);
+ /** @phpstan-ignore argument.type */
return new MetricExporter($transport, Temporality::CUMULATIVE);
}
- private function createMeter(string $type, string $name, callable $creator): mixed
+ /**
+ * @template T of Counter|UpDownCounter|Histogram|Gauge
+ * @param class-string $type
+ * @param callable(): T $creator
+ * @return T
+ */
+ private function createMeter(string $type, string $name, callable $creator): Counter|UpDownCounter|Histogram|Gauge
{
- if (!isset($this->meterStorage[$type][$name])) {
+ if (! isset($this->meterStorage[$type][$name])) {
$this->meterStorage[$type][$name] = $creator();
}
+ /** @var T */
return $this->meterStorage[$type][$name];
}
+ /**
+ * Create a Counter metric
+ *
+ * @param array $advisory
+ */
public function createCounter(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Counter
{
- $counter = $this->createMeter(Counter::class, $name, fn () => $this->meter->createCounter($name, $unit, $description, $advisory));
- return new class ($counter) extends Counter {
- public function __construct(private CounterInterface $counter)
- {
- }
- public function add(float|int $amount, iterable $attributes = []): void
- {
- $this->counter->add($amount, $attributes);
- }
- };
+ return $this->createMeter(Counter::class, $name, function () use ($name, $unit, $description, $advisory) {
+ $counter = $this->meter->createCounter($name, $unit, $description, $advisory);
+
+ return new class ($counter) extends Counter {
+ public function __construct(private CounterInterface $counter)
+ {
+ }
+
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
+ public function add(float|int $amount, iterable $attributes = []): void
+ {
+ $this->counter->add($amount, $attributes);
+ }
+ };
+ });
}
+ /**
+ * Create a Histogram metric
+ *
+ * @param array $advisory
+ */
public function createHistogram(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Histogram
{
- $histogram = $this->createMeter(Histogram::class, $name, fn () => $this->meter->createHistogram($name, $unit, $description, $advisory));
- return new class ($histogram) extends Histogram {
- public function __construct(private HistogramInterface $histogram)
- {
- }
- public function record(float|int $amount, iterable $attributes = []): void
- {
- $this->histogram->record($amount, $attributes);
- }
- };
+ return $this->createMeter(Histogram::class, $name, function () use ($name, $unit, $description, $advisory) {
+ $histogram = $this->meter->createHistogram($name, $unit, $description, $advisory);
+
+ return new class ($histogram) extends Histogram {
+ public function __construct(private HistogramInterface $histogram)
+ {
+ }
+
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
+ public function record(float|int $amount, iterable $attributes = []): void
+ {
+ $this->histogram->record($amount, $attributes);
+ }
+ };
+ });
}
+ /**
+ * Create a Gauge metric
+ *
+ * @param array $advisory
+ */
public function createGauge(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Gauge
{
- $gauge = $this->createMeter(Gauge::class, $name, fn () => $this->meter->createGauge($name, $unit, $description, $advisory));
- return new class ($gauge) extends Gauge {
- public function __construct(private GaugeInterface $gauge)
- {
- }
- public function record(float|int $amount, iterable $attributes = []): void
- {
- $this->gauge->record($amount, $attributes);
- }
- };
+ return $this->createMeter(Gauge::class, $name, function () use ($name, $unit, $description, $advisory) {
+ $gauge = $this->meter->createGauge($name, $unit, $description, $advisory);
+
+ return new class ($gauge) extends Gauge {
+ public function __construct(private GaugeInterface $gauge)
+ {
+ }
+
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
+ public function record(float|int $amount, iterable $attributes = []): void
+ {
+ $this->gauge->record($amount, $attributes);
+ }
+ };
+ });
}
+ /**
+ * Create an UpDownCounter metric
+ *
+ * @param array $advisory
+ */
public function createUpDownCounter(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): UpDownCounter
{
- $upDownCounter = $this->createMeter(UpDownCounter::class, $name, fn () => $this->meter->createUpDownCounter($name, $unit, $description, $advisory));
- return new class ($upDownCounter) extends UpDownCounter {
- public function __construct(private UpDownCounterInterface $upDownCounter)
- {
- }
- public function add(float|int $amount, iterable $attributes = []): void
- {
- $this->upDownCounter->add($amount, $attributes);
- }
- };
+ return $this->createMeter(UpDownCounter::class, $name, function () use ($name, $unit, $description, $advisory) {
+ $upDownCounter = $this->meter->createUpDownCounter($name, $unit, $description, $advisory);
+
+ return new class ($upDownCounter) extends UpDownCounter {
+ public function __construct(private UpDownCounterInterface $upDownCounter)
+ {
+ }
+
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
+ public function add(float|int $amount, iterable $attributes = []): void
+ {
+ $this->upDownCounter->add($amount, $attributes);
+ }
+ };
+ });
}
+ /**
+ * Collect and export metrics
+ */
public function collect(): bool
{
return $this->reader->collect();
diff --git a/src/Telemetry/Adapter/OpenTelemetry/Transport/Swoole.php b/src/Telemetry/Adapter/OpenTelemetry/Transport/Swoole.php
new file mode 100644
index 0000000..2530a6f
--- /dev/null
+++ b/src/Telemetry/Adapter/OpenTelemetry/Transport/Swoole.php
@@ -0,0 +1,212 @@
+
+ */
+class Swoole implements TransportInterface
+{
+ private string $host;
+ private int $port;
+ private string $path;
+ private bool $ssl;
+
+ /** @var array Pre-computed base headers */
+ private array $baseHeaders;
+
+ /** @var array Pre-computed client settings */
+ private array $settings;
+
+ private Channel $pool;
+ private int $poolSize;
+
+ private Atomic $shutdown;
+
+ /**
+ * @param 'application/json'|'application/x-ndjson'|'application/x-protobuf' $contentType
+ * @param array $headers
+ */
+ public function __construct(
+ string $endpoint,
+ private string $contentType = ContentTypes::PROTOBUF,
+ private array $headers = [],
+ private float $timeout = 10.0,
+ int $poolSize = 8,
+ int $socketBufferSize = 64 * 1024, // 64 KB
+ ) {
+ $parsed = parse_url($endpoint);
+ if ($parsed === false) {
+ throw new \InvalidArgumentException("Invalid endpoint URL: {$endpoint}");
+ }
+
+ $this->ssl = ($parsed['scheme'] ?? 'http') === 'https';
+ $this->host = $parsed['host'] ?? 'localhost';
+ $this->port = $parsed['port'] ?? ($this->ssl ? 443 : 80);
+ $this->path = $parsed['path'] ?? '/';
+ if (isset($parsed['query'])) {
+ $this->path .= '?' . $parsed['query'];
+ }
+
+ $this->poolSize = $poolSize;
+ $this->shutdown = new Atomic(0);
+ $this->pool = new Channel($this->poolSize);
+
+ $this->baseHeaders = \array_merge(
+ [
+ 'Content-Type' => $this->contentType,
+ 'Connection' => 'keep-alive',
+ ],
+ $this->headers
+ );
+ $this->settings = [
+ 'timeout' => $this->timeout,
+ 'connect_timeout' => \max(0.5, $this->timeout),
+ 'read_timeout' => \max(1.0, $this->timeout),
+ 'write_timeout' => \max(1.0, $this->timeout),
+ 'keep_alive' => true,
+ 'open_tcp_nodelay' => true,
+ 'open_tcp_keepalive' => true,
+ 'tcp_keepidle' => 60,
+ 'tcp_keepinterval' => 5,
+ 'tcp_keepcount' => 3,
+ 'socket_buffer_size' => $socketBufferSize,
+ 'http_compression' => false,
+ ];
+ }
+
+ /**
+ * Get the content type used for requests.
+ *
+ * @return string
+ */
+ public function contentType(): string
+ {
+ return $this->contentType;
+ }
+
+ /**
+ * @return FutureInterface
+ */
+ public function send(string $payload, ?CancellationInterface $cancellation = null): FutureInterface
+ {
+ if ($this->shutdown->get() === 1) {
+ return new ErrorFuture(new Exception('Transport has been shut down'));
+ }
+
+ $client = null;
+ $forceClose = false;
+
+ try {
+ $client = $this->popClient();
+ $headers = $this->baseHeaders;
+ $headers['Content-Length'] = \strlen($payload);
+ $client->setHeaders($headers);
+ $client->post($this->path, $payload);
+ $statusCode = $client->getStatusCode();
+
+ // Connection error (timeout, reset, etc.)
+ if ($statusCode < 0) {
+ $forceClose = true;
+ $errCode = \is_int($client->errCode) ? $client->errCode : 0;
+ $errMsg = \is_string($client->errMsg) ? $client->errMsg : 'Unknown error';
+
+ return new ErrorFuture(new Exception("OTLP connection failed: {$errMsg} (code: {$errCode})"));
+ }
+
+ $body = $client->getBody();
+ $bodyStr = \is_string($body) ? $body : '';
+
+ if ($statusCode >= 200 && $statusCode < 300) {
+ return new CompletedFuture($bodyStr);
+ }
+
+ // Server error may need fresh connection
+ if ($statusCode >= 500) {
+ $forceClose = true;
+ }
+
+ $statusCodeStr = \is_int($statusCode) ? (string)$statusCode : 'unknown';
+ return new ErrorFuture(new Exception("OTLP export failed with status {$statusCodeStr}: {$bodyStr}"));
+ } catch (\Throwable $e) {
+ $forceClose = true;
+
+ return new ErrorFuture($e);
+ } finally {
+ if ($client !== null) {
+ $this->putClient($client, $forceClose);
+ }
+ }
+ }
+
+ /**
+ * Acquire a client from the pool or create a new one.
+ */
+ private function popClient(): Client
+ {
+ $client = $this->pool->pop(0.001);
+ if ($client === false) {
+ $client = $this->pool->pop(0.05);
+ }
+ if ($client instanceof Client) {
+ if ($client->connected) {
+ return $client;
+ }
+ $client->close();
+ }
+
+ $client = new Client($this->host, $this->port, $this->ssl);
+ $client->set($this->settings);
+
+ return $client;
+ }
+
+ /**
+ * Return a client to the pool or close it.
+ */
+ private function putClient(Client $client, bool $forceClose = false): void
+ {
+ if ($this->shutdown->get() === 1 || $forceClose || !$client->connected) {
+ $client->close();
+ return;
+ }
+ if (!$this->pool->push($client, 1.0)) {
+ $client->close();
+ }
+ }
+
+ public function shutdown(?CancellationInterface $cancellation = null): bool
+ {
+ $this->shutdown->set(1);
+
+ // Drain and close all pooled connections
+ while (!$this->pool->isEmpty()) {
+ $client = $this->pool->pop(0.001);
+ if ($client instanceof Client) {
+ $client->close();
+ }
+ }
+ $this->pool->close();
+
+ return true;
+ }
+
+ public function forceFlush(?CancellationInterface $cancellation = null): bool
+ {
+ return true;
+ }
+}
diff --git a/src/Telemetry/Adapter/Test.php b/src/Telemetry/Adapter/Test.php
index 7688597..74df1e0 100644
--- a/src/Telemetry/Adapter/Test.php
+++ b/src/Telemetry/Adapter/Test.php
@@ -13,15 +13,40 @@
*/
class Test implements Adapter
{
+ /**
+ * @var array
+ */
public array $counters = [];
+
+ /**
+ * @var array
+ */
public array $histograms = [];
+
+ /**
+ * @var array
+ */
public array $gauges = [];
+
+ /**
+ * @var array
+ */
public array $upDownCounters = [];
+ /**
+ * @param array $advisory
+ */
public function createCounter(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Counter
{
$counter = new class () extends Counter {
+ /**
+ * @var array
+ */
public array $values = [];
+
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
public function add(float|int $amount, iterable $attributes = []): void
{
$this->values[] = $amount;
@@ -31,10 +56,20 @@ public function add(float|int $amount, iterable $attributes = []): void
return $counter;
}
+ /**
+ * @param array $advisory
+ */
public function createHistogram(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Histogram
{
$histogram = new class () extends Histogram {
+ /**
+ * @var array
+ */
public array $values = [];
+
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
public function record(float|int $amount, iterable $attributes = []): void
{
$this->values[] = $amount;
@@ -44,10 +79,20 @@ public function record(float|int $amount, iterable $attributes = []): void
return $histogram;
}
+ /**
+ * @param array $advisory
+ */
public function createGauge(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): Gauge
{
$gauge = new class () extends Gauge {
+ /**
+ * @var array
+ */
public array $values = [];
+
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
public function record(float|int $amount, iterable $attributes = []): void
{
$this->values[] = $amount;
@@ -57,10 +102,20 @@ public function record(float|int $amount, iterable $attributes = []): void
return $gauge;
}
+ /**
+ * @param array $advisory
+ */
public function createUpDownCounter(string $name, ?string $unit = null, ?string $description = null, array $advisory = []): UpDownCounter
{
$upDownCounter = new class () extends UpDownCounter {
+ /**
+ * @var array
+ */
public array $values = [];
+
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
public function add(float|int $amount, iterable $attributes = []): void
{
$this->values[] = $amount;
diff --git a/src/Telemetry/Counter.php b/src/Telemetry/Counter.php
index 6d00365..c08a5ad 100644
--- a/src/Telemetry/Counter.php
+++ b/src/Telemetry/Counter.php
@@ -4,5 +4,8 @@
abstract class Counter
{
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
abstract public function add(float|int $amount, iterable $attributes = []): void;
}
diff --git a/src/Telemetry/Exception.php b/src/Telemetry/Exception.php
new file mode 100644
index 0000000..8dd38a9
--- /dev/null
+++ b/src/Telemetry/Exception.php
@@ -0,0 +1,7 @@
+|bool|float|int|string|null> $attributes
+ */
abstract public function record(float|int $amount, iterable $attributes = []): void;
}
diff --git a/src/Telemetry/Histogram.php b/src/Telemetry/Histogram.php
index 27cc919..f423bec 100644
--- a/src/Telemetry/Histogram.php
+++ b/src/Telemetry/Histogram.php
@@ -4,5 +4,8 @@
abstract class Histogram
{
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
abstract public function record(float|int $amount, iterable $attributes = []): void;
}
diff --git a/src/Telemetry/UpDownCounter.php b/src/Telemetry/UpDownCounter.php
index 98a9648..4d1fbce 100644
--- a/src/Telemetry/UpDownCounter.php
+++ b/src/Telemetry/UpDownCounter.php
@@ -4,5 +4,8 @@
abstract class UpDownCounter
{
+ /**
+ * @param iterable|bool|float|int|string|null> $attributes
+ */
abstract public function add(float|int $amount, iterable $attributes = []): void;
}
diff --git a/tests/Telemetry/Adapter/OpenTelemetry/Swoole/MockOtlpServer.php b/tests/Telemetry/Adapter/OpenTelemetry/Swoole/MockOtlpServer.php
new file mode 100644
index 0000000..d9640af
--- /dev/null
+++ b/tests/Telemetry/Adapter/OpenTelemetry/Swoole/MockOtlpServer.php
@@ -0,0 +1,216 @@
+, timestamp: float}> */
+ private array $requests = [];
+
+ private int $statusCode = 200;
+
+ private string $responseBody = '';
+
+ private float $responseDelay = 0;
+
+ public function __construct()
+ {
+ $this->port = self::HOST === '127.0.0.1' ? 19318 + (self::$portOffset++) : 19318;
+ }
+
+ /**
+ * Get the endpoint URL for this server.
+ */
+ public function getEndpoint(): string
+ {
+ return 'http://'.self::HOST.':'.$this->port.'/v1/metrics';
+ }
+
+ /**
+ * Get just the port number.
+ */
+ public function getPort(): int
+ {
+ return $this->port;
+ }
+
+ /**
+ * Configure the response status code.
+ */
+ public function respondWith(int $statusCode, string $body = ''): self
+ {
+ $this->statusCode = $statusCode;
+ $this->responseBody = $body;
+
+ return $this;
+ }
+
+ /**
+ * Add artificial delay to responses (for testing timeouts/concurrency).
+ */
+ public function withDelay(float $seconds): self
+ {
+ $this->responseDelay = $seconds;
+
+ return $this;
+ }
+
+ /**
+ * Start the server (non-blocking).
+ */
+ public function start(): void
+ {
+ $this->server = new Server(self::HOST, $this->port);
+ $this->server->set(['open_http2_protocol' => false]);
+
+ $this->server->handle('/v1/metrics', function (Request $request, Response $response) {
+ $this->requests[] = [
+ 'payload' => $request->getContent(),
+ 'headers' => $request->header,
+ 'timestamp' => microtime(true),
+ ];
+
+ if ($this->responseDelay > 0) {
+ Coroutine::sleep($this->responseDelay);
+ }
+
+ $response->status($this->statusCode);
+ $response->end($this->responseBody);
+ });
+
+ go(fn () => $this->server->start());
+
+ $this->waitUntilReady();
+ }
+
+ /**
+ * Stop the server.
+ */
+ public function stop(): void
+ {
+ $this->server->shutdown();
+ }
+
+ /**
+ * Wait for the server to be ready to accept connections.
+ *
+ * @throws Exception If the server fails to start within the timeout period
+ */
+ private function waitUntilReady(float $timeout = 2.0): void
+ {
+ $start = microtime(true);
+ while (microtime(true) - $start < $timeout) {
+ $client = new Client(self::HOST, $this->port);
+ $client->set(['timeout' => 0.1]);
+ $client->get('/');
+ if ($client->statusCode !== -1 && $client->statusCode !== -2) {
+ $client->close();
+
+ return;
+ }
+ $client->close();
+ Coroutine::sleep(0.01);
+ }
+
+ throw new Exception(sprintf(
+ 'MockOtlpServer failed to start: could not connect to %s:%d within %.1f seconds',
+ self::HOST,
+ $this->port,
+ $timeout
+ ));
+ }
+
+ /**
+ * Get all captured requests.
+ *
+ * @return array, timestamp: float}>
+ */
+ public function getRequests(): array
+ {
+ return $this->requests;
+ }
+
+ /**
+ * Get the number of requests received.
+ */
+ public function getRequestCount(): int
+ {
+ return count($this->requests);
+ }
+
+ /**
+ * Get the last request received.
+ *
+ * @return array{payload: string, headers: array, timestamp: float}|null
+ */
+ public function getLastRequest(): ?array
+ {
+ return $this->requests[count($this->requests) - 1] ?? null;
+ }
+
+ /**
+ * Clear captured requests.
+ */
+ public function reset(): void
+ {
+ $this->requests = [];
+ }
+
+ /**
+ * Run a test with a mock server, handling lifecycle automatically.
+ *
+ * If already inside a coroutine, runs directly. Otherwise wraps in run().
+ *
+ * @param callable(MockOtlpServer): void $test
+ */
+ public static function run(callable $test): void
+ {
+ $exception = null;
+
+ $executor = function () use ($test, &$exception) {
+ $server = new self();
+ $server->start();
+
+ try {
+ $test($server);
+ } catch (\Throwable $e) {
+ $exception = $e;
+ } finally {
+ $server->stop();
+ }
+ };
+
+ if (Coroutine::getCid() > 0) {
+ $executor();
+ } else {
+ run($executor);
+ }
+
+ if ($exception !== null) {
+ throw $exception;
+ }
+ }
+}
diff --git a/tests/Telemetry/Adapter/OpenTelemetry/Swoole/TransportIntegrationTest.php b/tests/Telemetry/Adapter/OpenTelemetry/Swoole/TransportIntegrationTest.php
new file mode 100644
index 0000000..8ae12f9
--- /dev/null
+++ b/tests/Telemetry/Adapter/OpenTelemetry/Swoole/TransportIntegrationTest.php
@@ -0,0 +1,227 @@
+respondWith(200, 'OK');
+
+ $transport = new Swoole($server->getEndpoint());
+ $testPayload = 'test-metric-payload-data';
+
+ $result = $transport->send($testPayload)->await();
+
+ $this->assertEquals('OK', $result);
+
+ $request = $server->getLastRequest();
+ $this->assertEquals($testPayload, $request['payload']);
+ $this->assertEquals(ContentTypes::PROTOBUF, $request['headers']['content-type']);
+ $this->assertEquals((string) strlen($testPayload), $request['headers']['content-length']);
+
+ $transport->shutdown();
+ });
+ }
+
+ public function testSendWithCustomHeaders(): void
+ {
+ MockOtlpServer::run(function (MockOtlpServer $server) {
+ $transport = new Swoole(
+ endpoint: $server->getEndpoint(),
+ headers: [
+ 'Authorization' => 'Bearer test-token',
+ 'X-Custom-Header' => 'custom-value',
+ ]
+ );
+
+ $transport->send('payload')->await();
+
+ $request = $server->getLastRequest();
+ $this->assertEquals('Bearer test-token', $request['headers']['authorization']);
+ $this->assertEquals('custom-value', $request['headers']['x-custom-header']);
+
+ $transport->shutdown();
+ });
+ }
+
+ public function testSendHandlesServerError(): void
+ {
+ MockOtlpServer::run(function (MockOtlpServer $server) {
+ $server->respondWith(500, 'Internal Server Error');
+
+ $transport = new Swoole($server->getEndpoint());
+
+ $this->expectException(Exception::class);
+ $this->expectExceptionMessage('500');
+
+ try {
+ $transport->send('payload')->await();
+ } finally {
+ $transport->shutdown();
+ }
+ });
+ }
+
+ public function testMultipleSequentialSends(): void
+ {
+ MockOtlpServer::run(function (MockOtlpServer $server) {
+ $transport = new Swoole(
+ endpoint: $server->getEndpoint(),
+ poolSize: 2,
+ );
+
+ for ($i = 0; $i < 10; $i++) {
+ $transport->send("payload-$i")->await();
+ }
+
+ $this->assertEquals(10, $server->getRequestCount());
+
+ $transport->shutdown();
+ });
+ }
+
+ public function testConcurrentSends(): void
+ {
+ MockOtlpServer::run(function (MockOtlpServer $server) {
+ $server->withDelay(0.01);
+
+ $transport = new Swoole(
+ endpoint: $server->getEndpoint(),
+ poolSize: 4,
+ );
+
+ $wg = new \Swoole\Coroutine\WaitGroup();
+ $concurrentRequests = 20;
+
+ for ($i = 0; $i < $concurrentRequests; $i++) {
+ $wg->add();
+ go(function () use ($transport, $i, $wg) {
+ $transport->send("concurrent-payload-$i")->await();
+ $wg->done();
+ });
+ }
+
+ $wg->wait();
+
+ $this->assertEquals($concurrentRequests, $server->getRequestCount());
+
+ $transport->shutdown();
+ });
+ }
+
+ public function testJsonContentType(): void
+ {
+ MockOtlpServer::run(function (MockOtlpServer $server) {
+ $transport = new Swoole(
+ endpoint: $server->getEndpoint(),
+ contentType: ContentTypes::JSON,
+ );
+
+ $transport->send('{"metrics":[]}')->await();
+
+ $request = $server->getLastRequest();
+ $this->assertEquals(ContentTypes::JSON, $request['headers']['content-type']);
+
+ $transport->shutdown();
+ });
+ }
+
+ public function testConnectionTimeout(): void
+ {
+ $exception = null;
+
+ run(function () use (&$exception) {
+ $transport = new Swoole(
+ endpoint: 'http://127.0.0.1:19999/v1/metrics',
+ timeout: 0.5,
+ );
+
+ $startTime = microtime(true);
+
+ try {
+ $transport->send('payload')->await();
+ } catch (Exception $e) {
+ $exception = $e;
+ } finally {
+ $elapsed = microtime(true) - $startTime;
+ $this->assertLessThan(2.0, $elapsed);
+ $transport->shutdown();
+ }
+ });
+
+ $this->assertNotNull($exception);
+ $this->assertInstanceOf(Exception::class, $exception);
+ }
+
+ public function testKeepAliveConnectionReuse(): void
+ {
+ MockOtlpServer::run(function (MockOtlpServer $server) {
+ $transport = new Swoole(
+ endpoint: $server->getEndpoint(),
+ poolSize: 1,
+ );
+
+ // Send 5 requests with pool size 1
+ for ($i = 0; $i < 5; $i++) {
+ $transport->send("payload-$i")->await();
+ }
+
+ $this->assertEquals(5, $server->getRequestCount());
+
+ $transport->shutdown();
+ });
+ }
+
+ public function testLargePayload(): void
+ {
+ MockOtlpServer::run(function (MockOtlpServer $server) {
+ $transport = new Swoole($server->getEndpoint());
+
+ // 1MB payload
+ $largePayload = str_repeat('x', 1024 * 1024);
+
+ $transport->send($largePayload)->await();
+
+ $request = $server->getLastRequest();
+ $this->assertEquals(strlen($largePayload), strlen($request['payload']));
+
+ $transport->shutdown();
+ });
+ }
+
+ public function testServerResetsRequestTracking(): void
+ {
+ MockOtlpServer::run(function (MockOtlpServer $server) {
+ $transport = new Swoole($server->getEndpoint());
+
+ $transport->send('first')->await();
+ $this->assertEquals(1, $server->getRequestCount());
+
+ $server->reset();
+ $this->assertEquals(0, $server->getRequestCount());
+
+ $transport->send('second')->await();
+ $this->assertEquals(1, $server->getRequestCount());
+
+ $transport->shutdown();
+ });
+ }
+}
diff --git a/tests/Telemetry/Adapter/OpenTelemetry/Swoole/TransportTest.php b/tests/Telemetry/Adapter/OpenTelemetry/Swoole/TransportTest.php
new file mode 100644
index 0000000..08682e7
--- /dev/null
+++ b/tests/Telemetry/Adapter/OpenTelemetry/Swoole/TransportTest.php
@@ -0,0 +1,210 @@
+assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testConstructorWithHttpEndpoint(): void
+ {
+ $transport = new Swoole('http://localhost:4318/v1/metrics');
+
+ $this->assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testConstructorWithCustomContentType(): void
+ {
+ $transport = new Swoole(
+ 'http://localhost:4318/v1/metrics',
+ ContentTypes::JSON
+ );
+
+ $this->assertEquals(ContentTypes::JSON, $transport->contentType());
+ }
+
+ public function testConstructorWithCustomHeaders(): void
+ {
+ $transport = new Swoole(
+ 'http://localhost:4318/v1/metrics',
+ ContentTypes::PROTOBUF,
+ ['Authorization' => 'Bearer token123']
+ );
+
+ $this->assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testConstructorWithCustomTimeout(): void
+ {
+ $transport = new Swoole(
+ 'http://localhost:4318/v1/metrics',
+ ContentTypes::PROTOBUF,
+ [],
+ 5.0
+ );
+
+ $this->assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testConstructorWithCustomPoolSize(): void
+ {
+ $transport = new Swoole(
+ 'http://localhost:4318/v1/metrics',
+ ContentTypes::PROTOBUF,
+ [],
+ 10.0,
+ 16
+ );
+
+ $this->assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testConstructorWithCustomSocketBufferSize(): void
+ {
+ $transport = new Swoole(
+ 'http://localhost:4318/v1/metrics',
+ ContentTypes::PROTOBUF,
+ [],
+ 10.0,
+ 8,
+ 128 * 1024
+ );
+
+ $this->assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testShutdownReturnsTrue(): void
+ {
+ $this->runInCoroutine(function () {
+ $transport = new Swoole('http://localhost:4318/v1/metrics');
+
+ $result = $transport->shutdown();
+
+ $this->assertTrue($result);
+ });
+ }
+
+ public function testForceFlushReturnsTrue(): void
+ {
+ $this->runInCoroutine(function () {
+ $transport = new Swoole('http://localhost:4318/v1/metrics');
+
+ $result = $transport->forceFlush();
+
+ $this->assertTrue($result);
+ });
+ }
+
+ public function testSendAfterShutdownReturnsError(): void
+ {
+ $this->runInCoroutine(function () {
+ $transport = new Swoole('http://localhost:4318/v1/metrics');
+
+ $transport->shutdown();
+
+ $future = $transport->send('test payload');
+
+ try {
+ $future->await();
+ $this->fail('Expected exception was not thrown');
+ } catch (Exception $e) {
+ $this->assertInstanceOf(Exception::class, $e);
+ $this->assertEquals('Transport has been shut down', $e->getMessage());
+ }
+ });
+ }
+
+ public function testMultipleShutdownsAreSafe(): void
+ {
+ $this->runInCoroutine(function () {
+ $transport = new Swoole('http://localhost:4318/v1/metrics');
+
+ $result1 = $transport->shutdown();
+ $result2 = $transport->shutdown();
+
+ $this->assertTrue($result1);
+ $this->assertTrue($result2);
+ });
+ }
+
+ public function testEndpointWithQueryString(): void
+ {
+ $transport = new Swoole('http://localhost:4318/v1/metrics?api_key=secret&env=test');
+
+ $this->assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testMalformedUrlThrowsException(): void
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Invalid endpoint URL');
+
+ new Swoole('http:///v1/metrics');
+ }
+
+ public function testDefaultPortForHttp(): void
+ {
+ $transport = new Swoole('http://example.com/v1/metrics');
+
+ $this->assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testDefaultPortForHttps(): void
+ {
+ $transport = new Swoole('https://example.com/v1/metrics');
+
+ $this->assertEquals(ContentTypes::PROTOBUF, $transport->contentType());
+ }
+
+ public function testContentTypeMatchesConstructor(): void
+ {
+ $jsonTransport = new Swoole('http://localhost:4318', ContentTypes::JSON);
+ $protobufTransport = new Swoole('http://localhost:4318', ContentTypes::PROTOBUF);
+
+ $this->assertEquals(ContentTypes::JSON, $jsonTransport->contentType());
+ $this->assertEquals(ContentTypes::PROTOBUF, $protobufTransport->contentType());
+ }
+}
diff --git a/tests/Telemetry/Adapter/OpenTelemetryTestCase.php b/tests/Telemetry/Adapter/OpenTelemetryTestCase.php
new file mode 100644
index 0000000..bab4da3
--- /dev/null
+++ b/tests/Telemetry/Adapter/OpenTelemetryTestCase.php
@@ -0,0 +1,238 @@
+ 'test-namespace',
+ 'name' => 'test-service',
+ 'instanceId' => 'test-instance-'.uniqid(),
+ ];
+ }
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+
+ $this->transport = $this->createTransport();
+ $config = $this->getServiceConfig();
+
+ $this->adapter = new OpenTelemetry(
+ endpoint: $this->getEndpoint(),
+ serviceNamespace: $config['namespace'],
+ serviceName: $config['name'],
+ serviceInstanceId: $config['instanceId'],
+ transport: $this->transport,
+ );
+ }
+
+ public function testCreateCounter(): void
+ {
+ $counter = $this->adapter->createCounter(
+ name: 'test_counter',
+ unit: 'requests',
+ description: 'Test counter metric'
+ );
+
+ $this->assertInstanceOf(Counter::class, $counter);
+ }
+
+ public function testCounterAdd(): void
+ {
+ $counter = $this->adapter->createCounter('add_test_counter');
+
+ // Should not throw
+ $counter->add(1);
+ $counter->add(5);
+ $counter->add(10, ['label' => 'value']);
+
+ $this->assertTrue(true);
+ }
+
+ public function testCreateHistogram(): void
+ {
+ $histogram = $this->adapter->createHistogram(
+ name: 'test_histogram',
+ unit: 'ms',
+ description: 'Test histogram metric'
+ );
+
+ $this->assertInstanceOf(Histogram::class, $histogram);
+ }
+
+ public function testHistogramRecord(): void
+ {
+ $histogram = $this->adapter->createHistogram('record_test_histogram');
+
+ // Should not throw
+ $histogram->record(100);
+ $histogram->record(250.5);
+ $histogram->record(50, ['endpoint' => '/api/test']);
+
+ $this->assertTrue(true);
+ }
+
+ public function testCreateGauge(): void
+ {
+ $gauge = $this->adapter->createGauge(
+ name: 'test_gauge',
+ unit: 'bytes',
+ description: 'Test gauge metric'
+ );
+
+ $this->assertInstanceOf(Gauge::class, $gauge);
+ }
+
+ public function testGaugeRecord(): void
+ {
+ $gauge = $this->adapter->createGauge('record_test_gauge');
+
+ // Should not throw
+ $gauge->record(1024);
+ $gauge->record(2048.5);
+ $gauge->record(512, ['host' => 'server-1']);
+
+ $this->assertTrue(true);
+ }
+
+ public function testCreateUpDownCounter(): void
+ {
+ $upDownCounter = $this->adapter->createUpDownCounter(
+ name: 'test_updown_counter',
+ unit: 'connections',
+ description: 'Test up-down counter metric'
+ );
+
+ $this->assertInstanceOf(UpDownCounter::class, $upDownCounter);
+ }
+
+ public function testUpDownCounterAdd(): void
+ {
+ $upDownCounter = $this->adapter->createUpDownCounter('add_test_updown');
+
+ // Should not throw
+ $upDownCounter->add(1);
+ $upDownCounter->add(-1);
+ $upDownCounter->add(5, ['pool' => 'main']);
+
+ $this->assertTrue(true);
+ }
+
+ public function testMeterCaching(): void
+ {
+ $counter1 = $this->adapter->createCounter('cached_counter');
+ $counter2 = $this->adapter->createCounter('cached_counter');
+
+ // Same name should return cached instance
+ $this->assertSame($counter1, $counter2);
+ }
+
+ public function testDifferentMetersNotCached(): void
+ {
+ $counter1 = $this->adapter->createCounter('counter_a');
+ $counter2 = $this->adapter->createCounter('counter_b');
+
+ // Different names should return different instances
+ $this->assertNotSame($counter1, $counter2);
+ }
+
+ public function testCollect(): void
+ {
+ $counter = $this->adapter->createCounter('collect_test_counter');
+ $counter->add(1);
+
+ $result = $this->adapter->collect();
+
+ $this->assertIsBool($result);
+ }
+
+ public function testMetricsWithAttributes(): void
+ {
+ $counter = $this->adapter->createCounter('attributed_counter');
+ $histogram = $this->adapter->createHistogram('attributed_histogram');
+ $gauge = $this->adapter->createGauge('attributed_gauge');
+ $upDownCounter = $this->adapter->createUpDownCounter('attributed_updown');
+
+ $attributes = [
+ 'service' => 'api',
+ 'environment' => 'test',
+ 'version' => '1.0.0',
+ ];
+
+ // All should accept attributes without throwing
+ $counter->add(1, $attributes);
+ $histogram->record(100, $attributes);
+ $gauge->record(50, $attributes);
+ $upDownCounter->add(1, $attributes);
+
+ $this->assertTrue(true);
+ }
+
+ public function testMetricsWithAdvisory(): void
+ {
+ // Create metrics with advisory parameters
+ $counter = $this->adapter->createCounter(
+ name: 'advisory_counter',
+ unit: 'items',
+ description: 'Counter with advisory',
+ advisory: ['explicit_bucket_boundaries' => [0, 5, 10, 25, 50, 100]]
+ );
+
+ $this->assertInstanceOf(Counter::class, $counter);
+ }
+
+ public function testNullOptionalParameters(): void
+ {
+ // All optional parameters as null
+ $counter = $this->adapter->createCounter('minimal_counter');
+ $histogram = $this->adapter->createHistogram('minimal_histogram');
+ $gauge = $this->adapter->createGauge('minimal_gauge');
+ $upDownCounter = $this->adapter->createUpDownCounter('minimal_updown');
+
+ $this->assertInstanceOf(Counter::class, $counter);
+ $this->assertInstanceOf(Histogram::class, $histogram);
+ $this->assertInstanceOf(Gauge::class, $gauge);
+ $this->assertInstanceOf(UpDownCounter::class, $upDownCounter);
+ }
+}