[Bridge\PhpUnit] Exit as late as possible

People might want to register other shutdown functions that should be
able to control the exit code themselves, without the deprecation error
handler taking over. The php manual says:

> If you call exit() within one registered shutdown function, processing
> will stop completely and no other registered shutdown functions will be
> called.

See https://secure.php.net/manual/en/function.register-shutdown-function.php
This commit is contained in:
Grégoire Paris 2018-02-01 23:45:44 +01:00 committed by Nicolas Grekas
parent 0924c001f9
commit 97370a3dd9
3 changed files with 133 additions and 16 deletions

View File

@ -127,32 +127,53 @@ class DeprecationErrorHandler
return $b['count'] - $a['count'];
};
foreach (array('unsilenced', 'remaining', 'legacy', 'other') as $group) {
if ($deprecations[$group.'Count']) {
echo "\n", $colorize(sprintf('%s deprecation notices (%d)', ucfirst($group), $deprecations[$group.'Count']), 'legacy' !== $group), "\n";
$displayDeprecations = function ($deprecations) use ($colorize, $cmp) {
foreach (array('unsilenced', 'remaining', 'legacy', 'other') as $group) {
if ($deprecations[$group.'Count']) {
echo "\n", $colorize(sprintf('%s deprecation notices (%d)', ucfirst($group), $deprecations[$group.'Count']), 'legacy' !== $group), "\n";
uasort($deprecations[$group], $cmp);
uasort($deprecations[$group], $cmp);
foreach ($deprecations[$group] as $msg => $notices) {
echo "\n ", $notices['count'], 'x: ', $msg, "\n";
foreach ($deprecations[$group] as $msg => $notices) {
echo "\n ", $notices['count'], 'x: ', $msg, "\n";
arsort($notices);
arsort($notices);
foreach ($notices as $method => $count) {
if ('count' !== $method) {
echo ' ', $count, 'x in ', preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method), "\n";
foreach ($notices as $method => $count) {
if ('count' !== $method) {
echo ' ', $count, 'x in ', preg_replace('/(.*)\\\\(.*?::.*?)$/', '$2 from $1', $method), "\n";
}
}
}
}
}
}
if (!empty($notices)) {
echo "\n";
if (!empty($notices)) {
echo "\n";
}
};
$displayDeprecations($deprecations);
// store failing status
$isFailing = 'weak' !== $mode && ($deprecations['unsilenced'] || $deprecations['remaining'] || $deprecations['other']);
// reset deprecations array
foreach ($deprecations as $group => $arrayOrInt) {
$deprecations[$group] = is_int($arrayOrInt) ? 0 : array();
}
if ('weak' !== $mode && ($deprecations['unsilenced'] || $deprecations['remaining'] || $deprecations['other'])) {
exit(1);
}
register_shutdown_function(function () use (&$deprecations, $isFailing, $displayDeprecations, $mode) {
foreach ($deprecations as $group => $arrayOrInt) {
if (0 < (is_int($arrayOrInt) ? $arrayOrInt : count($arrayOrInt))) {
echo "Shutdown-time deprecations:\n";
break;
}
}
$displayDeprecations($deprecations);
if ($isFailing || 'weak' !== $mode && ($deprecations['unsilenced'] || $deprecations['remaining'] || $deprecations['other'])) {
exit(1);
}
});
});
}
}

View File

@ -59,6 +59,10 @@ $foo = new FooTestCase();
$foo->testLegacyFoo();
$foo->testNonLegacyBar();
register_shutdown_function(function () {
exit('I get precedence over any exit statements inside the deprecation error handler.');
});
?>
--EXPECTF--
Unsilenced deprecation notices (3)
@ -80,3 +84,4 @@ Other deprecation notices (1)
1x: root deprecation
I get precedence over any exit statements inside the deprecation error handler.

View File

@ -0,0 +1,91 @@
--TEST--
Test DeprecationErrorHandler in default mode
--FILE--
<?php
putenv('SYMFONY_DEPRECATIONS_HELPER');
putenv('ANSICON');
putenv('ConEmuANSI');
putenv('TERM');
$vendor = __DIR__;
while (!file_exists($vendor.'/vendor')) {
$vendor = dirname($vendor);
}
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
require PHPUNIT_COMPOSER_INSTALL;
require_once __DIR__.'/../../bootstrap.php';
@trigger_error('root deprecation', E_USER_DEPRECATED);
eval(<<<'EOPHP'
namespace PHPUnit\Util;
class Test
{
public static function getGroups()
{
return array();
}
}
EOPHP
);
class PHPUnit_Util_Test
{
public static function getGroups()
{
return array();
}
}
class FooTestCase
{
public function testLegacyFoo()
{
@trigger_error('silenced foo deprecation', E_USER_DEPRECATED);
trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED);
trigger_error('unsilenced foo deprecation', E_USER_DEPRECATED);
}
public function testNonLegacyBar()
{
@trigger_error('silenced bar deprecation', E_USER_DEPRECATED);
trigger_error('unsilenced bar deprecation', E_USER_DEPRECATED);
}
}
$foo = new FooTestCase();
$foo->testLegacyFoo();
$foo->testNonLegacyBar();
register_shutdown_function(function () {
@trigger_error('root deprecation during shutdown', E_USER_DEPRECATED);
});
?>
--EXPECTF--
Unsilenced deprecation notices (3)
2x: unsilenced foo deprecation
2x in FooTestCase::testLegacyFoo
1x: unsilenced bar deprecation
1x in FooTestCase::testNonLegacyBar
Remaining deprecation notices (1)
1x: silenced bar deprecation
1x in FooTestCase::testNonLegacyBar
Legacy deprecation notices (1)
Other deprecation notices (1)
1x: root deprecation
Shutdown-time deprecations:
Other deprecation notices (1)
1x: root deprecation during shutdown