From ab543f3ffce825f3ac4d17ee4643f8a6dec0d899 Mon Sep 17 00:00:00 2001 From: mskayali Date: Wed, 21 Oct 2026 21:22:25 +0300 Subject: [PATCH] feat: Add support for PHP 8.4 and 8.5 The SDK cannot be installed on PHP 8.4 or 8.5 because composer.json pins `"php": ">=8.1 <8.4"`. Three deprecations also surface on those versions. 1. `ParseException::__construct()` declared `Exception $previous = null`. Implicitly nullable parameters are deprecated as of PHP 8.4. 2. `ParseStream::getFileContents()` read the locally scoped `$http_response_header`, deprecated as of PHP 8.5 in favour of `http_get_last_response_headers()`. 3. `ParseCurl::close()` called `curl_close()`, deprecated as of PHP 8.5 because it has had no effect since PHP 8.0. The legacy header read is null coalesced on purpose. On PHP 8.5 a direct read of `$http_response_header` raises the deprecation at compile time, so it fires even when the branch never runs, and even inside `isset()`. Four patterns measured on 8.5.8 and 8.5.12: isset($http_response_header) ? $http_response_header : [] deprecation $http_response_header deprecation $http_response_header ?? [] none get_defined_vars()['http_response_header'] ?? [] none A `function_exists()` guard alone is therefore not sufficient. Verification: all 42 files under src/ pass `php -l` with `error_reporting=E_ALL` on PHP 8.5, and a live request through the patched `getFileContents()` returns the response headers on 8.3.32, 8.4.26, 8.5.8 and 8.5.12, with `HTTP/1.1 200 OK` as the first entry. The upper bound follows #520, which moved to `<8.4` when 8.3 landed. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 4 ++++ composer.json | 2 +- src/Parse/HttpClients/ParseCurl.php | 7 +++---- src/Parse/HttpClients/ParseStream.php | 17 ++++++++++++++++- src/Parse/ParseException.php | 2 +- 5 files changed, 25 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b8564b5b..728a8dbf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,6 +27,10 @@ jobs: strategy: matrix: include: + - name: PHP 8.5 + PHP_VERSION: 8.5 + - name: PHP 8.4 + PHP_VERSION: 8.4 - name: PHP 8.3 PHP_VERSION: 8.3 - name: PHP 8.2 diff --git a/composer.json b/composer.json index 4c6332dc..7e06af00 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ } ], "require": { - "php": ">=8.1 <8.4", + "php": ">=8.1 <8.6", "ext-curl": "*", "ext-json": "*" }, diff --git a/src/Parse/HttpClients/ParseCurl.php b/src/Parse/HttpClients/ParseCurl.php index 17cf2fbc..52348552 100644 --- a/src/Parse/HttpClients/ParseCurl.php +++ b/src/Parse/HttpClients/ParseCurl.php @@ -133,10 +133,9 @@ public function close() throw new ParseException('You must call ParseCurl::init first'); } - // close our handle - curl_close($this->curl); - - // unset our curl handle + // PHP 8.5 deprecates curl_close(); it has had no effect since PHP + // 8.0, when CurlHandle became an object released on last reference. + // Unsetting the handle below is what actually closes it. $this->curl = null; } } diff --git a/src/Parse/HttpClients/ParseStream.php b/src/Parse/HttpClients/ParseStream.php index b6845f70..d18a47c0 100644 --- a/src/Parse/HttpClients/ParseStream.php +++ b/src/Parse/HttpClients/ParseStream.php @@ -110,7 +110,22 @@ public function getErrorCode() public function getFileContents($filename, $use_include_path, $context) { $result = file_get_contents($filename, $use_include_path, $context); - $this->responseHeaders = $http_response_header; + + // PHP 8.5 deprecated the locally scoped `$http_response_header` + // variable in favour of `http_get_last_response_headers()`. That + // function does not exist before 8.5, so both paths are kept. + // + // The legacy read uses `??` deliberately: a direct read raises the + // deprecation at compile time on 8.5, even inside `isset()`, while + // a null coalesced read does not. + $hasHeaderFunction = \function_exists( + 'http_get_last_response_headers' + ); + + $this->responseHeaders = $hasHeaderFunction + ? (http_get_last_response_headers() ?? []) + : ($http_response_header ?? []); + return $result; } } diff --git a/src/Parse/ParseException.php b/src/Parse/ParseException.php index 2f46c886..d65b058a 100644 --- a/src/Parse/ParseException.php +++ b/src/Parse/ParseException.php @@ -22,7 +22,7 @@ class ParseException extends Exception * @param int $code Error code. * @param \Exception $previous Previous Exception. */ - public function __construct($message, $code = 0, Exception $previous = null) + public function __construct($message, $code = 0, ?Exception $previous = null) { parent::__construct($message, $code, $previous); }