-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[Framework bundle] Cleanup error and exception handlers on Kernel shutdown #53812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Isn't this something that |
IMO it should not be bound to a sf test case. Users usually extend their testcase and cannot extend another one. It should be something that can be triggered via composition, not inheritance. |
This issue is a blocker for PHPUnit 11 in any Symfony project that uses |
this is not a root cause. I'd correct that to:
E.g. for me the test maintenance is much easier when I'm not relying on SF testcases so I can extend my own leaner testcase. I use Kernel via composition in tests. So the root cause is that there's no way to cleanup after Kernel, not some test case. |
Same issue "Test code or tested code did not remove its own exception handlers" here with
|
I had the same problem with Symfony 6.4 and PHPUnit 11. I temporarily solved it by calling this method in the protected function restoreExceptionHandler(): void
{
while (true) {
$previousHandler = set_exception_handler(static fn() => null);
restore_exception_handler();
if ($previousHandler === null) {
break;
}
restore_exception_handler();
}
} The protected function tearDown(): void
{
parent::tearDown();
$this->restoreExceptionHandler();
} It is based on what Laravel did on their testsuite: https://github.com/laravel/framework/pull/49622/files Maybe the solution is to call a similar method in the |
Currently, I cleanup exceptions like this: $res = [];
while (true) {
$previousHandler = set_exception_handler(static fn () => null);
restore_exception_handler();
if (
is_array($previousHandler)
&& $previousHandler[0] instanceof \Symfony\Component\ErrorHandler\ErrorHandler
&& $previousHandler[1] === 'handleException'
) {
restore_exception_handler();
continue;
}
if ($previousHandler === null) {
break;
}
$res[] = $previousHandler;
restore_exception_handler();
}
$res = array_reverse($res);
foreach ($res as $handler) {
set_exception_handler($handler);
} The same for errors |
A different workaround, seeing as the Symfony/Errorhandler is a singleton and will only register once, is to register the error handler before phpunit memorizes all the existing error handlers. This way the error handler Symfony register's is not new. Create (or modify) <?php
declare(strict_types=1);
use Symfony\Component\ErrorHandler\ErrorHandler;
ErrorHandler::register(null, false); and in <?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.0/phpunit.xsd"
bootstrap="tests/bootstrap.php">
...
</phpunit> |
@frankdekker is right, the error handler registered by FrameworkBundle would not replace the active error handler. PHPUnit already registers its own error handler and that one is still active at the end of the test. So we're good here. The problem which PHPUnit reports is about the exception handler. Yes, error handler and exception handler are two different things. And yes, it's super confusing that Symfony has a method called PHPUnit on the other hand does not register an exception handler and even if it did, that handler would be wrapped by But. <?php
declare(strict_types=1);
use Symfony\Component\ErrorHandler\ErrorHandler;
require dirname(__DIR__).'/vendor/autoload.php';
set_exception_handler([new ErrorHandler(), 'handleException']); That being said, this feels like a hack. Maybe we should add a way to opt out of the exception handler. In situations where the kernel is executed within a huge try/catch block (which a PHPUnit test basically is), that exception handler does not serve any purpose anyway. |
workaround for symfony/symfony#53812 (comment)
thanks very much @derrabus, you're very simple addition to my pre-existing
I agree with you that, while simple, it does seem somewhat like a hack. I am wondering if the symfony maintainers plan to take on your suggestion, perhaps by offering a new config option to opt out of the error handler that defaults to |
Will this issue be resolved by symfony or is it expected to add @derrabus solution to every project? |
This will be resolved by whomever resolves it. Could be you? |
otherwise risky checks are warned symfony/symfony#53812
What if we stopped registering error handlers, exception handlers or shutdown functions of any kind in FrameworkBundle? We do need this stuff way before the framework is booted, so whatever FrameworkBundle registers here, it does it way too late. This applies especially to exception handlers: They are meant to handle uncaught exceptions. The kernel however runs in a big try/catch, so at the time FrameworkBundle is booted, the need for an exception handler is more or less over. In modern Symfony applications, the error handling should be set up by the runtime already. All that FrameworkBundle does is connecting the logger properly. The logic that registers an error handler or exception handler is usually dormant and causes trouble because PHPUnit tests run outside of the runtime. |
This would require deprecating the FrameworkBundle configuration settings that allow configuring the error handler though |
Would it? I mean, FWB can still connect to the error handler registered by the runtime and reconfigure it. |
This comment has been minimized.
This comment has been minimized.
…wn exception handlers Фикс взят из symfony/symfony#53812
I tried these fixes and they didn't fix the issue for me. I'm not sure why. Our codebase/test suite originates all the way from Laravel 5.8 so perhaps there's something there (though we've done our best to continuously modernise the codebase). |
@nicolas-grekas thanks for the merge, but I am somewhat confused. The commit mentions it was merged into 5.4 branch 2 weeks ago, but the latest 5.4 release is 3 weeks old (5.4.44). And no indication as to whether the fix will also be merged into 6.4 and 7.x. Can you clarify, or am I by chance missing something? The latest |
We regularly merge bugfixes up into all maintained branches which means that the fix will ship with the next patch releases of 5.4, 6.4 and 7.1. |
Ahh okay, thanks!! |
As xabbuh said, it has been merged to the 6.4 branch: 33050e3 And the last release on So it's not yet available but it will come to 6.4 at some point, but I don't know the release process of the minor versions so I can't tell when. |
Thank you both for your patience with my silly question. I should have know, and think I did, but just forgot how the versioned branches work. Thanks again :) |
The patch is in the 6.4 branch now, but the problem remains. |
@garak Can you then please create a small example application that allows to reproduce? |
I believe my statement here is not fair, it's very specific to my project, I can't seem to reproduce the problem, see: |
Fair point, I've tried a few different scenarios. All are working fine, so can only conclude it's a library that we are using that is interfering. Already tried a few, still can't reproduce. I'll let you know when I find something! |
I did a short test by rebasing the @sulu branch for PHPUnit 11 interesting is that currently in case of Sulu only the
Update Something seems to block the framework bundle upgrade. Intersting that I get on ![]()
Found the issue in my case a update of |
I've had similar issue that was caused by a workaround in zenstruck/foundry. Opened an issue there: |
As suggested in symfony/symfony#53812 (comment) This seems like a temporary fix, until symfony has figured out what to do with sebastianbergmann/phpunit#5619 Issue: ecamp#6407
interesting. this problem is absent on symfony 6.4, but exists in latest 7.2 |
We were held back by symfony/symfony#53812 The issue is that `FrameworkBundle` registers an exception handler (if `ErrorHandler` was not registered before as an exception handler) and never removes it when the Kernel shuts down. PHPUnit checks for newly registered exception handlers at the end of each test, so whenever the kernel boots, PHPUnit sees a "dangling" exception handlers and issues a warning. Now that the issue is closed with a documented workaround (but not a proper solution in `FrameworkBundle`) the only way forward seems to be the workaround. "Workaround" means registering the Symfony error handler *before* starting PHPUnit, which will skip the additional registration in `FrameworkBundle`. Ticket: https://phabricator.wikimedia.org/T359971
Symfony version(s) affected
7.0.0
Description
PHPUnit 11 checks for any leftovers in error handlers sebastianbergmann/phpunit#5619
How to reproduce
Run
FrameworkBundle->boot()
in phpunit test.symfony/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
Line 98 in 815df93
It results in
Test code or tested code did not remove its own exception handlers
thrown by phpunit.Possible Solution
Introduce
FrameworkBundle::shutdown()
that would cleanup error handler set inboot()
. IMO it's reasonable to have some cleanup in shutdown() of things initiated in boot().Additional Context
No response
The text was updated successfully, but these errors were encountered: