bug #37959 [PhpunitBridge] Fix deprecation type detection (when several autoload files are used) (l-vo)

This PR was merged into the 4.4 branch.

Discussion
----------

[PhpunitBridge] Fix deprecation type detection (when several autoload files are used)

| Q             | A
| ------------- | ---
| Branch?       | 4.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       |
| License       | MIT
| Doc PR        |

Several autoload files are supported by the PHPUnit Bridge but when the internal paths are registered (for deprecation type detection), the paths (from prefixes) of the last autoload file override the paths previously registered. This PR fixes this bug.

Commits
-------

cc7b6c5e5a [PhpunitBridge] Fix deprecation type detection
This commit is contained in:
Fabien Potencier 2020-09-02 16:59:26 +02:00
commit 52719f2800
8 changed files with 167 additions and 5 deletions

View File

@ -266,7 +266,10 @@ class Deprecation
if (file_exists($v.'/composer/installed.json')) {
self::$vendors[] = $v;
$loader = require $v.'/autoload.php';
$paths = self::getSourcePathsFromPrefixes(array_merge($loader->getPrefixes(), $loader->getPrefixesPsr4()));
$paths = self::addSourcePathsFromPrefixes(
array_merge($loader->getPrefixes(), $loader->getPrefixesPsr4()),
$paths
);
}
}
}
@ -282,15 +285,17 @@ class Deprecation
return self::$vendors;
}
private static function getSourcePathsFromPrefixes(array $prefixesByNamespace)
private static function addSourcePathsFromPrefixes(array $prefixesByNamespace, array $paths)
{
foreach ($prefixesByNamespace as $prefixes) {
foreach ($prefixes as $prefix) {
if (false !== realpath($prefix)) {
yield realpath($prefix);
$paths[] = realpath($prefix);
}
}
}
return $paths;
}
/**

View File

@ -0,0 +1,19 @@
<?php
namespace App\Services;
use acme\lib\SomeService;
use foo\lib\SomeOtherService;
final class AppService
{
public function directDeprecations()
{
$service1 = new SomeService();
$service1->deprecatedApi();
$service2 = new SomeOtherService();
$service2->deprecatedApi();
}
}

View File

@ -9,14 +9,40 @@ class ComposerLoaderFake
public function getPrefixesPsr4()
{
return [];
return [
'App\\Services\\' => [__DIR__.'/../../fake_app/'],
'acme\\lib\\' => [__DIR__.'/../acme/lib/'],
];
}
public function loadClass($className)
{
foreach ($this->getPrefixesPsr4() as $prefix => $baseDirs) {
if (strpos($className, $prefix) !== 0) {
continue;
}
foreach ($baseDirs as $baseDir) {
$file = str_replace([$prefix, '\\'], [$baseDir, '/'], $className.'.php');
if (file_exists($file)) {
require $file;
}
}
}
}
}
class ComposerAutoloaderInitFake
{
private static $loader;
public static function getLoader()
{
return new ComposerLoaderFake();
if (null === self::$loader) {
self::$loader = new ComposerLoaderFake();
spl_autoload_register([self::$loader, 'loadClass']);
}
return self::$loader;
}
}

View File

@ -0,0 +1,5 @@
<?php
require_once __DIR__.'/composer/autoload_real.php';
return ComposerAutoloaderInitFakeBis::getLoader();

View File

@ -0,0 +1,47 @@
<?php
class ComposerLoaderFakeBis
{
public function getPrefixes()
{
return [];
}
public function getPrefixesPsr4()
{
return [
'foo\\lib\\' => [__DIR__.'/../foo/lib/'],
];
}
public function loadClass($className)
{
foreach ($this->getPrefixesPsr4() as $prefix => $baseDirs) {
if (strpos($className, $prefix) !== 0) {
continue;
}
foreach ($baseDirs as $baseDir) {
$file = str_replace([$prefix, '\\'], [$baseDir, '/'], $className.'.php');
if (file_exists($file)) {
require $file;
}
}
}
}
}
class ComposerAutoloaderInitFakeBis
{
private static $loader;
public static function getLoader()
{
if (null === self::$loader) {
self::$loader = new ComposerLoaderFakeBis();
spl_autoload_register([self::$loader, 'loadClass']);
}
return self::$loader;
}
}

View File

@ -0,0 +1 @@
{"just here": "for the detection"}

View File

@ -0,0 +1,14 @@
<?php
namespace foo\lib;
class SomeOtherService
{
public function deprecatedApi()
{
@trigger_error(
__FUNCTION__.' from foo is deprecated! You should stop relying on it!',
E_USER_DEPRECATED
);
}
}

View File

@ -0,0 +1,45 @@
--TEST--
Test DeprecationErrorHandler with multiple autoload files
--FILE--
<?php
$k = 'SYMFONY_DEPRECATIONS_HELPER';
putenv($k.'='.$_SERVER[$k] = $_ENV[$k] = 'max[self]=0');
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';
eval(<<<'EOPHP'
namespace PHPUnit\Util;
class Test
{
public static function getGroups()
{
return array();
}
}
EOPHP
);
require __DIR__.'/fake_vendor/autoload.php';
require __DIR__.'/fake_vendor_bis/autoload.php';
(new \App\Services\AppService())->directDeprecations();
?>
--EXPECTF--
Remaining direct deprecation notices (2)
1x: deprecatedApi is deprecated! You should stop relying on it!
1x in AppService::directDeprecations from App\Services
1x: deprecatedApi from foo is deprecated! You should stop relying on it!
1x in AppService::directDeprecations from App\Services