diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8bf17f21..f35f1d60 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -24,6 +24,7 @@ jobs: - php: '8.2' - php: '8.3' - php: '8.4' + - php: '8.5' fail-fast: false steps: diff --git a/README.md b/README.md index 7517fba8..5b5c913e 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ Polyfills are provided for: - the `Deprecated` attribute introduced in PHP 8.4; - the `mb_trim`, `mb_ltrim` and `mb_rtrim` functions introduced in PHP 8.4; - the `CURL_HTTP_VERSION_3` and `CURL_HTTP_VERSION_3ONLY` constants introduced in PHP 8.4; +- the `get_error_handler` and `get_exception_handler` functions introduced in PHP 8.5; It is strongly recommended to upgrade your PHP version and/or install the missing extensions whenever possible. This polyfill should be used only when there is no @@ -105,6 +106,7 @@ should **not** `require` the `symfony/polyfill` package, but the standalone ones - `symfony/polyfill-php82` for using the PHP 8.2 functions, - `symfony/polyfill-php83` for using the PHP 8.3 functions, - `symfony/polyfill-php84` for using the PHP 8.4 functions, +- `symfony/polyfill-php85` for using the PHP 8.5 functions, - `symfony/polyfill-iconv` for using the iconv functions, - `symfony/polyfill-intl-grapheme` for using the `grapheme_*` functions, - `symfony/polyfill-intl-idn` for using the `idn_to_ascii` and `idn_to_utf8` functions, diff --git a/composer.json b/composer.json index a639d51c..3ac20a3a 100644 --- a/composer.json +++ b/composer.json @@ -33,6 +33,7 @@ "symfony/polyfill-php82": "self.version", "symfony/polyfill-php83": "self.version", "symfony/polyfill-php84": "self.version", + "symfony/polyfill-php85": "self.version", "symfony/polyfill-iconv": "self.version", "symfony/polyfill-intl-grapheme": "self.version", "symfony/polyfill-intl-icu": "self.version", diff --git a/src/Php85/LICENSE b/src/Php85/LICENSE new file mode 100644 index 00000000..bc38d714 --- /dev/null +++ b/src/Php85/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2025-present Fabien Potencier + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/src/Php85/Php85.php b/src/Php85/Php85.php new file mode 100644 index 00000000..a406fe0e --- /dev/null +++ b/src/Php85/Php85.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Php85; + +/** + * @author Pierre Ambroise + * + * @internal + */ +final class Php85 +{ + public static function get_error_handler(): ?callable + { + $handler = set_error_handler(null); + restore_error_handler(); + + return $handler; + } + + public static function get_exception_handler(): ?callable + { + $handler = set_exception_handler(null); + restore_exception_handler(); + + return $handler; + } +} diff --git a/src/Php85/README.md b/src/Php85/README.md new file mode 100644 index 00000000..2ac492ab --- /dev/null +++ b/src/Php85/README.md @@ -0,0 +1,14 @@ +Symfony Polyfill / Php85 +======================== + +This component provides features added to PHP 8.5 core: + +- [`get_error_handler` and `get_exception_handler`](https://wiki.php.net/rfc/get-error-exception-handler) + +More information can be found in the +[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md). + +License +======= + +This library is released under the [MIT license](LICENSE). diff --git a/src/Php85/bootstrap.php b/src/Php85/bootstrap.php new file mode 100644 index 00000000..0da63eb9 --- /dev/null +++ b/src/Php85/bootstrap.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Polyfill\Php85 as p; + +if (\PHP_VERSION_ID >= 80500) { + return; +} + +if (!function_exists('get_error_handler')) { + function get_error_handler(): ?callable { return p\Php85::get_error_handler(); } +} + +if (!function_exists('get_exception_handler')) { + function get_exception_handler(): ?callable { return p\Php85::get_exception_handler(); } +} diff --git a/src/Php85/composer.json b/src/Php85/composer.json new file mode 100644 index 00000000..26bedf53 --- /dev/null +++ b/src/Php85/composer.json @@ -0,0 +1,32 @@ +{ + "name": "symfony/polyfill-php85", + "type": "library", + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "keywords": ["polyfill", "shim", "compatibility", "portable"], + "homepage": "https://symfony.com", + "license": "MIT", + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "require": { + "php": ">=7.2" + }, + "autoload": { + "psr-4": { "Symfony\\Polyfill\\Php85\\": "" }, + "files": [ "bootstrap.php" ] + }, + "minimum-stability": "dev", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + } +} diff --git a/src/bootstrap.php b/src/bootstrap.php index 56a216d5..aa7e46e3 100644 --- a/src/bootstrap.php +++ b/src/bootstrap.php @@ -36,3 +36,7 @@ if (\PHP_VERSION_ID < 80400) { require __DIR__.'/Php84/bootstrap.php'; } + +if (\PHP_VERSION_ID < 80500) { + require __DIR__.'/Php85/bootstrap.php'; +} diff --git a/tests/Php85/Php85Test.php b/tests/Php85/Php85Test.php new file mode 100644 index 00000000..fc4c7163 --- /dev/null +++ b/tests/Php85/Php85Test.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Polyfill\Tests\Php85; + +use PHPUnit\Framework\TestCase; + +class Php85Test extends TestCase +{ + /** + * @dataProvider provideHandler + */ + public function testGetErrorHandler($expected, $handler): void + { + set_error_handler($handler); + try { + $result = get_error_handler(); + } finally { + restore_error_handler(); + } + + $this->assertSame($expected, $result); + } + + public function testErrorStableReturnValue(): void + { + $this->assertSame(get_error_handler(), get_error_handler()); + } + + /** + * @dataProvider provideHandler + */ + public function testGetExceptionHandler($expected, $handler): void + { + set_exception_handler($handler); + try { + $result = get_exception_handler(); + } finally { + restore_exception_handler(); + } + + $this->assertSame($expected, $result); + } + + public function testExceptionStableReturnValue(): void + { + $this->assertSame(get_exception_handler(), get_exception_handler()); + + } + + public static function provideHandler() + { + // String handler + yield ['var_dump', 'var_dump']; + + // Null handler + yield [null, null]; + + // Static method array handler + yield [[TestHandler::class, 'handleStatic'], [TestHandler::class, 'handleStatic']]; + + // Static method string handler + yield ['Symfony\Polyfill\Tests\Php85\TestHandler::handleStatic', 'Symfony\Polyfill\Tests\Php85\TestHandler::handleStatic']; + + // Instance method array + $handler = new TestHandler(); + yield [[$handler, 'handle'], [$handler, 'handle']]; + + // Invokable object + $handler = new TestHandlerInvokable(); + yield [$handler, $handler]; + } +} + +class TestHandler +{ + public static function handleStatic() {} + public function handle() {} +} + +class TestHandlerInvokable +{ + public function __invoke() {} +}