Skip to content

Commit cf620b6

Browse files
committed
[PhpUnitBridge] Fix qualification of deprecations triggered by the debug class loader
1 parent 3a5e4cf commit cf620b6

File tree

9 files changed

+115
-3
lines changed

9 files changed

+115
-3
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
vendor/
22
composer.lock
33
phpunit.xml
4+
Tests/DeprecationErrorHandler/fake_vendor/symfony/error-handler/DebugClassLoader.php

DeprecationErrorHandler/Deprecation.php

+14
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
use PHPUnit\Util\Test;
1515
use Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerFor;
16+
use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader;
17+
use Symfony\Component\ErrorHandler\DebugClassLoader;
1618

1719
/**
1820
* @internal
@@ -53,6 +55,18 @@ class Deprecation
5355
public function __construct($message, array $trace, $file)
5456
{
5557
$this->trace = $trace;
58+
59+
if ('trigger_error' === ($trace[1]['function'] ?? null)
60+
&& (DebugClassLoader::class === ($class = $trace[2]['class'] ?? null) || LegacyDebugClassLoader::class === $class)
61+
&& 'checkClass' === ($trace[2]['function'] ?? null)
62+
&& null !== ($extraFile = $trace[2]['args'][1] ?? null)
63+
&& '' !== $extraFile
64+
&& false !== $extraFile = realpath($extraFile)
65+
) {
66+
$this->getOriginalFilesStack();
67+
array_splice($this->originalFilesStack, 2, 1, $extraFile);
68+
}
69+
5670
$this->message = $message;
5771
$i = \count($trace);
5872
while (1 < $i && $this->lineShouldBeSkipped($trace[--$i])) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
Test that a deprecation from the DebugClassLoader on a vendor class autoload triggered by an app class is considered indirect.
3+
--FILE--
4+
<?php
5+
6+
$k = 'SYMFONY_DEPRECATIONS_HELPER';
7+
putenv($k.'='.$_SERVER[$k] = $_ENV[$k] = 'max[total]=0');
8+
putenv('ANSICON');
9+
putenv('ConEmuANSI');
10+
putenv('TERM');
11+
12+
$vendor = __DIR__;
13+
while (!file_exists($vendor.'/vendor')) {
14+
$vendor = dirname($vendor);
15+
}
16+
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
17+
require PHPUNIT_COMPOSER_INSTALL;
18+
require_once __DIR__.'/../../bootstrap.php';
19+
eval(<<<'EOPHP'
20+
namespace PHPUnit\Util;
21+
22+
class Test
23+
{
24+
public static function getGroups()
25+
{
26+
return array();
27+
}
28+
}
29+
EOPHP
30+
);
31+
require __DIR__.'/fake_vendor/autoload.php';
32+
33+
// We need the real DebugClassLoader FQCN but in a vendor path.
34+
if (!file_exists($errorHandlerRootDir = __DIR__.'/../../../../Component/ErrorHandler')) {
35+
if (!file_exists($errorHandlerRootDir = __DIR__.'/../../vendor/symfony/error-handler')) {
36+
die('Could not find the ErrorHandler component root directory.');
37+
}
38+
}
39+
40+
file_put_contents($fakeDebugClassLoadPath = __DIR__.'/fake_vendor/symfony/error-handler/DebugClassLoader.php', file_get_contents($errorHandlerRootDir.'/DebugClassLoader.php'));
41+
require $fakeDebugClassLoadPath;
42+
43+
\Symfony\Component\ErrorHandler\DebugClassLoader::enable();
44+
new \App\Services\BarService();
45+
46+
?>
47+
--EXPECTF--
48+
Remaining indirect deprecation notices (1)
49+
50+
1x: The "acme\lib\ExtendsDeprecatedClassFromOtherVendor" class extends "fcy\lib\DeprecatedClass" that is deprecated.
51+
1x in BarService::__construct from App\Services
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace App\Services;
4+
5+
use acme\lib\ExtendsDeprecatedClassFromOtherVendor;
6+
7+
final class BarService
8+
{
9+
public function __construct()
10+
{
11+
ExtendsDeprecatedClassFromOtherVendor::FOO;
12+
}
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace acme\lib;
4+
5+
use fcy\lib\DeprecatedClass;
6+
7+
final class ExtendsDeprecatedClassFromOtherVendor extends DeprecatedClass
8+
{
9+
public const FOO = 'bar';
10+
}

Tests/DeprecationErrorHandler/fake_vendor/composer/autoload_real.php

+13-3
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,33 @@ public function getPrefixesPsr4()
1212
return [
1313
'App\\Services\\' => [__DIR__.'/../../fake_app/'],
1414
'acme\\lib\\' => [__DIR__.'/../acme/lib/'],
15+
'fcy\\lib\\' => [__DIR__.'/../fcy/lib/'],
1516
];
1617
}
1718

1819
public function loadClass($className)
20+
{
21+
if ($file = $this->findFile($className)) {
22+
require $file;
23+
}
24+
}
25+
26+
public function findFile($class)
1927
{
2028
foreach ($this->getPrefixesPsr4() as $prefix => $baseDirs) {
21-
if (strpos($className, $prefix) !== 0) {
29+
if (strpos($class, $prefix) !== 0) {
2230
continue;
2331
}
2432

2533
foreach ($baseDirs as $baseDir) {
26-
$file = str_replace([$prefix, '\\'], [$baseDir, '/'], $className.'.php');
34+
$file = str_replace([$prefix, '\\'], [$baseDir, '/'], $class.'.php');
2735
if (file_exists($file)) {
28-
require $file;
36+
return $file;
2937
}
3038
}
3139
}
40+
41+
return false;
3242
}
3343
}
3444

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace fcy\lib;
4+
5+
/**
6+
* @deprecated
7+
*/
8+
class DeprecatedClass
9+
{
10+
}

Tests/DeprecationErrorHandler/fake_vendor/symfony/error-handler/.gitkeep

Whitespace-only changes.

composer.json

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
"php": "THIS BRIDGE WHEN TESTING LOWEST SYMFONY VERSIONS.",
2121
"php": ">=5.5.9"
2222
},
23+
"require-dev": {
24+
"symfony/error-handler": "^4.4|^5.0"
25+
},
2326
"suggest": {
2427
"symfony/error-handler": "For tracking deprecated interfaces usages at runtime with DebugClassLoader"
2528
},

0 commit comments

Comments
 (0)