From 1cf767ebd7bbfb7f29c33e62b9fdf4e4f9ac2235 Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 29 Aug 2025 11:01:20 +0200 Subject: [PATCH 1/6] ci: Add 8.5 with ignoring dependencies --- .github/workflows/continuous-integration.yml | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 3b763a78..d1f47380 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -21,22 +21,14 @@ jobs: strategy: fail-fast: false matrix: - php-version: - - "7.2" - - "7.3" - - "7.4" - - "8.0" - - "8.1" - - "8.2" - - "8.3" - - "8.4" + php-version: [ '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] dependencies: [highest] include: - php-version: "7.2" dependencies: lowest -# - php-version: "8.5" -# dependencies: highest -# experimental: true + - php-version: "8.5" + dependencies: ignore + experimental: true steps: - name: "Checkout" From e11d6ff28217e21e0c0958dcb696419e94c438e3 Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 29 Aug 2025 11:16:56 +0200 Subject: [PATCH 2/6] refactor: Guard reflection setAccessible calls with PHP version check --- tests/Constraints/TypeTest.php | 8 ++++++-- tests/SchemaStorageTest.php | 6 ++++-- tests/Uri/Retrievers/FileGetContentsTest.php | 4 +++- tests/Uri/UriRetrieverTest.php | 16 ++++++++++++---- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/tests/Constraints/TypeTest.php b/tests/Constraints/TypeTest.php index 0aa830cb..8292b9b7 100644 --- a/tests/Constraints/TypeTest.php +++ b/tests/Constraints/TypeTest.php @@ -96,7 +96,9 @@ public function testValidateTypeNameWording($nameWording): void $t = new TypeConstraint(); $r = new \ReflectionObject($t); $m = $r->getMethod('validateTypeNameWording'); - $m->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $m->setAccessible(true); + } $m->invoke($t, $nameWording); $this->expectNotToPerformAssertions(); @@ -107,7 +109,9 @@ public function testInvalidateTypeNameWording(): void $t = new TypeConstraint(); $r = new \ReflectionObject($t); $m = $r->getMethod('validateTypeNameWording'); - $m->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $m->setAccessible(true); + } $this->expectException('\UnexpectedValueException'); $this->expectExceptionMessage("No wording for 'notAValidTypeName' available, expected wordings are: [an integer, a number, a boolean, an object, an array, a string, a null]"); diff --git a/tests/SchemaStorageTest.php b/tests/SchemaStorageTest.php index 502a5821..942aa43b 100644 --- a/tests/SchemaStorageTest.php +++ b/tests/SchemaStorageTest.php @@ -290,11 +290,13 @@ public function testNoDoubleResolve(): void $uriRetriever->retrieve('test/schema')->willReturn($schemaOne)->shouldBeCalled(); $s = new SchemaStorage($uriRetriever->reveal()); - $schema = $s->addSchema('test/schema'); + $s->addSchema('test/schema'); $r = new \ReflectionObject($s); $p = $r->getProperty('schemas'); - $p->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $p->setAccessible(true); + } $schemas = $p->getValue($s); $this->assertEquals( diff --git a/tests/Uri/Retrievers/FileGetContentsTest.php b/tests/Uri/Retrievers/FileGetContentsTest.php index d48d7945..70effd7c 100644 --- a/tests/Uri/Retrievers/FileGetContentsTest.php +++ b/tests/Uri/Retrievers/FileGetContentsTest.php @@ -31,7 +31,9 @@ public function testContentType(): void $reflector = new \ReflectionObject($res); $fetchContentType = $reflector->getMethod('fetchContentType'); - $fetchContentType->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $fetchContentType->setAccessible(true); + } $this->assertTrue($fetchContentType->invoke($res, ['Content-Type: application/json'])); $this->assertFalse($fetchContentType->invoke($res, ['X-Some-Header: whateverValue'])); diff --git a/tests/Uri/UriRetrieverTest.php b/tests/Uri/UriRetrieverTest.php index 0016cc4a..9d41b3c8 100644 --- a/tests/Uri/UriRetrieverTest.php +++ b/tests/Uri/UriRetrieverTest.php @@ -267,11 +267,15 @@ private function mockRetriever($schema): void $retrieverMock = $this->getRetrieverMock($schema); $factory = new \ReflectionProperty(\JsonSchema\Constraints\BaseConstraint::class, 'factory'); - $factory->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $factory->setAccessible(true); + } $factory = $factory->getValue($this->validator); $retriever = new \ReflectionProperty(\JsonSchema\Constraints\Factory::class, 'uriRetriever'); - $retriever->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $retriever->setAccessible(true); + } $retriever->setValue($factory, $retrieverMock); } @@ -362,12 +366,16 @@ public function testSchemaCache(): void // inject a schema cache value $schemaCache = $reflector->getProperty('schemaCache'); - $schemaCache->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $schemaCache->setAccessible(true); + } $schemaCache->setValue($retriever, ['local://test/uri' => 'testSchemaValue']); // retrieve from schema cache $loadSchema = $reflector->getMethod('loadSchema'); - $loadSchema->setAccessible(true); + if (PHP_VERSION_ID < 80100) { + $loadSchema->setAccessible(true); + } $this->assertEquals( 'testSchemaValue', $loadSchema->invoke($retriever, 'local://test/uri') From 45d261a15b11382d39a82ae79c22bc2f78be32d3 Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 29 Aug 2025 11:25:11 +0200 Subject: [PATCH 3/6] refactor: Guard curl_close only being called when PHP version is less than 8.0.0 --- src/JsonSchema/Uri/Retrievers/Curl.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/JsonSchema/Uri/Retrievers/Curl.php b/src/JsonSchema/Uri/Retrievers/Curl.php index 116607ae..311f1d34 100644 --- a/src/JsonSchema/Uri/Retrievers/Curl.php +++ b/src/JsonSchema/Uri/Retrievers/Curl.php @@ -53,7 +53,9 @@ public function retrieve($uri) $this->fetchMessageBody($response); $this->fetchContentType($response); - curl_close($ch); + if (PHP_VERSION_ID < 80000) { + curl_close($ch); + } return $this->messageBody; } From 6fe4a97b15bc39ca021c7bc4d8be12240610207e Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 29 Aug 2025 11:33:54 +0200 Subject: [PATCH 4/6] refactor: Improve $http_response_header forward compatibilty to avoid false positives See https://github.com/php/php-src/pull/19611, keeping the deprecated variable name leads to false positives --- .../Uri/Retrievers/FileGetContents.php | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/JsonSchema/Uri/Retrievers/FileGetContents.php b/src/JsonSchema/Uri/Retrievers/FileGetContents.php index cfb28d6f..9398d872 100644 --- a/src/JsonSchema/Uri/Retrievers/FileGetContents.php +++ b/src/JsonSchema/Uri/Retrievers/FileGetContents.php @@ -51,17 +51,17 @@ public function retrieve($uri) } $this->messageBody = $response; + if (function_exists('http_get_last_response_headers')) { - // Use http_get_last_response_headers() for BC compatibility with PHP 8.5+ - // where $http_response_header is deprecated. - $http_response_header = http_get_last_response_headers(); + $httpResponseHeaders = http_get_last_response_headers(); + } else { + /** @phpstan-ignore nullCoalesce.variable ($http_response_header can non-existing when no request was made) */ + $httpResponseHeaders = $http_response_header ?? []; } - if (!empty($http_response_header)) { - // $http_response_header cannot be tested, because it's defined in the method's local scope - // See http://php.net/manual/en/reserved.variables.httpresponseheader.php for more info. - $this->fetchContentType($http_response_header); // @codeCoverageIgnore - } else { // @codeCoverageIgnore - // Could be a "file://" url or something else - fake up the response + + if (!empty($httpResponseHeaders)) { + $this->fetchContentType($httpResponseHeaders); + } else { $this->contentType = null; } @@ -73,7 +73,7 @@ public function retrieve($uri) * * @return bool Whether the Content-Type header was found or not */ - private function fetchContentType(array $headers) + private function fetchContentType(array $headers): bool { foreach (array_reverse($headers) as $header) { if ($this->contentType = self::getContentTypeMatchInHeader($header)) { From e2d8d06c4ea0e4e34fb7051e238deb73ca10add1 Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 29 Aug 2025 12:13:05 +0200 Subject: [PATCH 5/6] docs: Add changelog entry --- CHANGELOG.md | 2 ++ src/JsonSchema/Uri/Retrievers/FileGetContents.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14d509ec..1d7b311d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- ### Changed +- ci: Add PHP 8.5 to pipeline, ignoring dependencies and as experimental ([#842](https://github.com/jsonrainbow/json-schema/pull/842)) ## [6.5.0] - 2025-08-29 ### Changed diff --git a/src/JsonSchema/Uri/Retrievers/FileGetContents.php b/src/JsonSchema/Uri/Retrievers/FileGetContents.php index 9398d872..f8eb2a84 100644 --- a/src/JsonSchema/Uri/Retrievers/FileGetContents.php +++ b/src/JsonSchema/Uri/Retrievers/FileGetContents.php @@ -55,7 +55,7 @@ public function retrieve($uri) if (function_exists('http_get_last_response_headers')) { $httpResponseHeaders = http_get_last_response_headers(); } else { - /** @phpstan-ignore nullCoalesce.variable ($http_response_header can non-existing when no request was made) */ + /** @phpstan-ignore nullCoalesce.variable ($http_response_header can non-existing when no http request was done) */ $httpResponseHeaders = $http_response_header ?? []; } From 382df37ba018df4b1b05d3471f262e44220e240a Mon Sep 17 00:00:00 2001 From: Danny van der Sluijs Date: Fri, 29 Aug 2025 12:50:21 +0200 Subject: [PATCH 6/6] docs: Restore comment --- src/JsonSchema/Uri/Retrievers/FileGetContents.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/JsonSchema/Uri/Retrievers/FileGetContents.php b/src/JsonSchema/Uri/Retrievers/FileGetContents.php index f8eb2a84..a4f96593 100644 --- a/src/JsonSchema/Uri/Retrievers/FileGetContents.php +++ b/src/JsonSchema/Uri/Retrievers/FileGetContents.php @@ -53,6 +53,8 @@ public function retrieve($uri) $this->messageBody = $response; if (function_exists('http_get_last_response_headers')) { + // Use http_get_last_response_headers() for compatibility with PHP 8.5+ + // where $http_response_header is deprecated. $httpResponseHeaders = http_get_last_response_headers(); } else { /** @phpstan-ignore nullCoalesce.variable ($http_response_header can non-existing when no http request was done) */