Skip to content

Commit b333bd1

Browse files
feature #521 Add get_*_handler polyfills (Fan2Shrek)
This PR was squashed before being merged into the 1.x branch. Discussion ---------- Add `get_*_handler` polyfills Here is the polyfill of newly implemented `get_error_handler` and `get_exception_handler`. I have created the default files for PHP 8.5 polyfills. The tests are taken from php/php-src#17693, but some cannot be completed due to new PHP 8 syntax. There are some issues with the error handler in the tests, I can't figure out why. If someone can help, that would be great! 😅 This seems to be related to the TestListenerTrait, I think. [RFC](https://wiki.php.net/rfc/get-error-exception-handler) Commits ------- d791faa Add `get_*_handler` polyfills
2 parents d139525 + d791faa commit b333bd1

File tree

10 files changed

+225
-0
lines changed

10 files changed

+225
-0
lines changed

.github/workflows/tests.yml

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
- php: '8.2'
2525
- php: '8.3'
2626
- php: '8.4'
27+
- php: '8.5'
2728
fail-fast: false
2829

2930
steps:

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ Polyfills are provided for:
7272
- the `Deprecated` attribute introduced in PHP 8.4;
7373
- the `mb_trim`, `mb_ltrim` and `mb_rtrim` functions introduced in PHP 8.4;
7474
- the `CURL_HTTP_VERSION_3` and `CURL_HTTP_VERSION_3ONLY` constants introduced in PHP 8.4;
75+
- the `get_error_handler` and `get_exception_handler` functions introduced in PHP 8.5;
7576

7677
It is strongly recommended to upgrade your PHP version and/or install the missing
7778
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
105106
- `symfony/polyfill-php82` for using the PHP 8.2 functions,
106107
- `symfony/polyfill-php83` for using the PHP 8.3 functions,
107108
- `symfony/polyfill-php84` for using the PHP 8.4 functions,
109+
- `symfony/polyfill-php85` for using the PHP 8.5 functions,
108110
- `symfony/polyfill-iconv` for using the iconv functions,
109111
- `symfony/polyfill-intl-grapheme` for using the `grapheme_*` functions,
110112
- `symfony/polyfill-intl-idn` for using the `idn_to_ascii` and `idn_to_utf8` functions,

composer.json

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"symfony/polyfill-php82": "self.version",
3434
"symfony/polyfill-php83": "self.version",
3535
"symfony/polyfill-php84": "self.version",
36+
"symfony/polyfill-php85": "self.version",
3637
"symfony/polyfill-iconv": "self.version",
3738
"symfony/polyfill-intl-grapheme": "self.version",
3839
"symfony/polyfill-intl-icu": "self.version",

src/Php85/LICENSE

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2025-present Fabien Potencier
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is furnished
8+
to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in all
11+
copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

src/Php85/Php85.php

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Polyfill\Php85;
13+
14+
/**
15+
* @author Pierre Ambroise <[email protected]>
16+
*
17+
* @internal
18+
*/
19+
final class Php85
20+
{
21+
public static function get_error_handler(): ?callable
22+
{
23+
$handler = set_error_handler(null);
24+
restore_error_handler();
25+
26+
return $handler;
27+
}
28+
29+
public static function get_exception_handler(): ?callable
30+
{
31+
$handler = set_exception_handler(null);
32+
restore_exception_handler();
33+
34+
return $handler;
35+
}
36+
}

src/Php85/README.md

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
Symfony Polyfill / Php85
2+
========================
3+
4+
This component provides features added to PHP 8.5 core:
5+
6+
- [`get_error_handler` and `get_exception_handler`](https://wiki.php.net/rfc/get-error-exception-handler)
7+
8+
More information can be found in the
9+
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
10+
11+
License
12+
=======
13+
14+
This library is released under the [MIT license](LICENSE).

src/Php85/bootstrap.php

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\Polyfill\Php85 as p;
13+
14+
if (\PHP_VERSION_ID >= 80500) {
15+
return;
16+
}
17+
18+
if (!function_exists('get_error_handler')) {
19+
function get_error_handler(): ?callable { return p\Php85::get_error_handler(); }
20+
}
21+
22+
if (!function_exists('get_exception_handler')) {
23+
function get_exception_handler(): ?callable { return p\Php85::get_exception_handler(); }
24+
}

src/Php85/composer.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"name": "symfony/polyfill-php85",
3+
"type": "library",
4+
"description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions",
5+
"keywords": ["polyfill", "shim", "compatibility", "portable"],
6+
"homepage": "https://symfony.com",
7+
"license": "MIT",
8+
"authors": [
9+
{
10+
"name": "Nicolas Grekas",
11+
"email": "[email protected]"
12+
},
13+
{
14+
"name": "Symfony Community",
15+
"homepage": "https://symfony.com/contributors"
16+
}
17+
],
18+
"require": {
19+
"php": ">=7.2"
20+
},
21+
"autoload": {
22+
"psr-4": { "Symfony\\Polyfill\\Php85\\": "" },
23+
"files": [ "bootstrap.php" ]
24+
},
25+
"minimum-stability": "dev",
26+
"extra": {
27+
"thanks": {
28+
"name": "symfony/polyfill",
29+
"url": "https://github.com/symfony/polyfill"
30+
}
31+
}
32+
}

src/bootstrap.php

+4
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,7 @@
3636
if (\PHP_VERSION_ID < 80400) {
3737
require __DIR__.'/Php84/bootstrap.php';
3838
}
39+
40+
if (\PHP_VERSION_ID < 80500) {
41+
require __DIR__.'/Php85/bootstrap.php';
42+
}

tests/Php85/Php85Test.php

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Polyfill\Tests\Php85;
13+
14+
use PHPUnit\Framework\TestCase;
15+
16+
class Php85Test extends TestCase
17+
{
18+
/**
19+
* @dataProvider provideHandler
20+
*/
21+
public function testGetErrorHandler($expected, $handler): void
22+
{
23+
set_error_handler($handler);
24+
try {
25+
$result = get_error_handler();
26+
} finally {
27+
restore_error_handler();
28+
}
29+
30+
$this->assertSame($expected, $result);
31+
}
32+
33+
public function testErrorStableReturnValue(): void
34+
{
35+
$this->assertSame(get_error_handler(), get_error_handler());
36+
}
37+
38+
/**
39+
* @dataProvider provideHandler
40+
*/
41+
public function testGetExceptionHandler($expected, $handler): void
42+
{
43+
set_exception_handler($handler);
44+
try {
45+
$result = get_exception_handler();
46+
} finally {
47+
restore_exception_handler();
48+
}
49+
50+
$this->assertSame($expected, $result);
51+
}
52+
53+
public function testExceptionStableReturnValue(): void
54+
{
55+
$this->assertSame(get_exception_handler(), get_exception_handler());
56+
57+
}
58+
59+
public static function provideHandler()
60+
{
61+
// String handler
62+
yield ['var_dump', 'var_dump'];
63+
64+
// Null handler
65+
yield [null, null];
66+
67+
// Static method array handler
68+
yield [[TestHandler::class, 'handleStatic'], [TestHandler::class, 'handleStatic']];
69+
70+
// Static method string handler
71+
yield ['Symfony\Polyfill\Tests\Php85\TestHandler::handleStatic', 'Symfony\Polyfill\Tests\Php85\TestHandler::handleStatic'];
72+
73+
// Instance method array
74+
$handler = new TestHandler();
75+
yield [[$handler, 'handle'], [$handler, 'handle']];
76+
77+
// Invokable object
78+
$handler = new TestHandlerInvokable();
79+
yield [$handler, $handler];
80+
}
81+
}
82+
83+
class TestHandler
84+
{
85+
public static function handleStatic() {}
86+
public function handle() {}
87+
}
88+
89+
class TestHandlerInvokable
90+
{
91+
public function __invoke() {}
92+
}

0 commit comments

Comments
 (0)