Skip to content

Commit ded5bdf

Browse files
Merge branch '4.4'
* 4.4: (43 commits) [PhpunitBridge] Read environment variable from superglobals [Bridge/PhpUnit] Fix PHP5.5 compat [PhpUnitBridge] More accurate grouping fixed CS [Form] remove comment about to-be-removed method as it is used in master by ButtonBuilder Extract unrecoverable exception to interface [FrameworkBundle] Fix calling Client::getProfile() before sending a request Fix type error [Security/Core] require libsodium >= 1.0.14 [Workflow] re-add workflow.definition tag to workflow services [Security/Core] Don't use ParagonIE_Sodium_Compat revert #30525 due to performance penalty collect called listeners information only once [Lock] fix missing inherit docs in RedisStore [Messenger] fix retrying handlers using DoctrineTransactionMiddleware [Mailgun Mailer] fixed issue when using html body [Messenger] make all stamps final and mark stamp not meant to be sent [HttpClient] fix timing measurements with NativeHttpClient add return type declaration use proper return types in ErrorHandler and ArgumentResolver ...
2 parents d3ccbc9 + cbb8d63 commit ded5bdf

12 files changed

+171
-72
lines changed

DeprecationErrorHandler.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,13 @@ public function handleError($type, $msg, $file, $line, $context = [])
134134
$group = 'unsilenced';
135135
} elseif ($deprecation->isLegacy(self::$utilPrefix)) {
136136
$group = 'legacy';
137-
} elseif (!$deprecation->isSelf()) {
138-
$group = $deprecation->isIndirect() ? 'remaining indirect' : 'remaining direct';
139137
} else {
140-
$group = 'remaining self';
138+
$group = [
139+
Deprecation::TYPE_SELF => 'remaining self',
140+
Deprecation::TYPE_DIRECT => 'remaining direct',
141+
Deprecation::TYPE_INDIRECT => 'remaining indirect',
142+
Deprecation::TYPE_UNDETERMINED => 'other',
143+
][$deprecation->getType()];
141144
}
142145

143146
if ($this->getConfiguration()->shouldDisplayStackTrace($msg)) {
@@ -211,7 +214,13 @@ private function getConfiguration()
211214
return $this->configuration;
212215
}
213216
if (false === $mode = $this->mode) {
214-
$mode = getenv('SYMFONY_DEPRECATIONS_HELPER');
217+
if (isset($_SERVER['SYMFONY_DEPRECATIONS_HELPER'])) {
218+
$mode = $_SERVER['SYMFONY_DEPRECATIONS_HELPER'];
219+
} elseif (isset($_ENV['SYMFONY_DEPRECATIONS_HELPER'])) {
220+
$mode = $_ENV['SYMFONY_DEPRECATIONS_HELPER'];
221+
} else {
222+
$mode = getenv('SYMFONY_DEPRECATIONS_HELPER');
223+
}
215224
}
216225
if ('strict' === $mode) {
217226
return $this->configuration = Configuration::inStrictMode();

DeprecationErrorHandler/Deprecation.php

Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@
1818
*/
1919
class Deprecation
2020
{
21+
const PATH_TYPE_VENDOR = 'path_type_vendor';
22+
const PATH_TYPE_SELF = 'path_type_internal';
23+
const PATH_TYPE_UNDETERMINED = 'path_type_undetermined';
24+
25+
const TYPE_SELF = 'type_self';
26+
const TYPE_DIRECT = 'type_direct';
27+
const TYPE_INDIRECT = 'type_indirect';
28+
const TYPE_UNDETERMINED = 'type_undetermined';
29+
2130
/**
2231
* @var array
2332
*/
@@ -39,13 +48,21 @@ class Deprecation
3948
private $originMethod;
4049

4150
/**
42-
* @var bool
51+
* @var string one of the PATH_TYPE_* constants
4352
*/
44-
private $self;
53+
private $triggeringFilePathType;
4554

4655
/** @var string[] absolute paths to vendor directories */
4756
private static $vendors;
4857

58+
/**
59+
* @var string[] absolute paths to source or tests of the project. This
60+
* excludes cache directories, because it is based on
61+
* autoloading rules and cache systems typically do not use
62+
* those.
63+
*/
64+
private static $internalPaths;
65+
4966
/**
5067
* @param string $message
5168
* @param string $file
@@ -59,7 +76,7 @@ public function __construct($message, array $trace, $file)
5976
// No-op
6077
}
6178
$line = $trace[$i];
62-
$this->self = !$this->pathOriginatesFromVendor($file);
79+
$this->trigerringFilePathType = $this->getPathType($file);
6380
if (isset($line['object']) || isset($line['class'])) {
6481
if (isset($line['class']) && 0 === strpos($line['class'], SymfonyTestsListenerFor::class)) {
6582
$parsedMsg = unserialize($this->message);
@@ -70,8 +87,9 @@ public function __construct($message, array $trace, $file)
7087
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
7188
// then we need to use the serialized information to determine
7289
// if the error has been triggered from vendor code.
73-
$this->self = isset($parsedMsg['triggering_file'])
74-
&& $this->pathOriginatesFromVendor($parsedMsg['triggering_file']);
90+
if (isset($parsedMsg['triggering_file'])) {
91+
$this->trigerringFilePathType = $this->getPathType($parsedMsg['triggering_file']);
92+
}
7593

7694
return;
7795
}
@@ -101,14 +119,6 @@ public function originatesFromAnObject()
101119
return isset($this->originClass);
102120
}
103121

104-
/**
105-
* @return bool
106-
*/
107-
public function isSelf()
108-
{
109-
return $this->self;
110-
}
111-
112122
/**
113123
* @return string
114124
*/
@@ -163,10 +173,16 @@ public function isLegacy($utilPrefix)
163173
* Tells whether both the calling package and the called package are vendor
164174
* packages.
165175
*
166-
* @return bool
176+
* @return string
167177
*/
168-
public function isIndirect()
178+
public function getType()
169179
{
180+
if (self::PATH_TYPE_SELF === $this->trigerringFilePathType) {
181+
return self::TYPE_SELF;
182+
}
183+
if (self::PATH_TYPE_UNDETERMINED === $this->trigerringFilePathType) {
184+
return self::TYPE_UNDETERMINED;
185+
}
170186
$erroringFile = $erroringPackage = null;
171187
foreach ($this->trace as $line) {
172188
if (\in_array($line['function'], ['require', 'require_once', 'include', 'include_once'], true)) {
@@ -179,25 +195,28 @@ public function isIndirect()
179195
if ('-' === $file || 'Standard input code' === $file || !realpath($file)) {
180196
continue;
181197
}
182-
if (!$this->pathOriginatesFromVendor($file)) {
183-
return false;
198+
if (self::PATH_TYPE_SELF === $this->getPathType($file)) {
199+
return self::TYPE_DIRECT;
200+
}
201+
if (self::PATH_TYPE_UNDETERMINED === $this->getPathType($file)) {
202+
return self::TYPE_UNDETERMINED;
184203
}
185204
if (null !== $erroringFile && null !== $erroringPackage) {
186205
$package = $this->getPackage($file);
187206
if ('composer' !== $package && $package !== $erroringPackage) {
188-
return true;
207+
return self::TYPE_INDIRECT;
189208
}
190209
continue;
191210
}
192211
$erroringFile = $file;
193212
$erroringPackage = $this->getPackage($file);
194213
}
195214

196-
return false;
215+
return self::TYPE_DIRECT;
197216
}
198217

199218
/**
200-
* pathOriginatesFromVendor() should always be called prior to calling this method.
219+
* getPathType() should always be called prior to calling this method.
201220
*
202221
* @param string $path
203222
*
@@ -237,6 +256,15 @@ private static function getVendors()
237256
$v = \dirname(\dirname($r->getFileName()));
238257
if (file_exists($v.'/composer/installed.json')) {
239258
self::$vendors[] = $v;
259+
$loader = require $v.'/autoload.php';
260+
$paths = self::getSourcePathsFromPrefixes(array_merge($loader->getPrefixes(), $loader->getPrefixesPsr4()));
261+
}
262+
}
263+
}
264+
foreach ($paths as $path) {
265+
foreach (self::$vendors as $vendor) {
266+
if (0 !== strpos($path, $vendor)) {
267+
self::$internalPaths[] = $path;
240268
}
241269
}
242270
}
@@ -245,24 +273,41 @@ private static function getVendors()
245273
return self::$vendors;
246274
}
247275

276+
private static function getSourcePathsFromPrefixes(array $prefixesByNamespace)
277+
{
278+
foreach ($prefixesByNamespace as $prefixes) {
279+
foreach ($prefixes as $prefix) {
280+
if (false !== realpath($prefix)) {
281+
yield realpath($prefix);
282+
}
283+
}
284+
}
285+
}
286+
248287
/**
249288
* @param string $path
250289
*
251-
* @return bool
290+
* @return string
252291
*/
253-
private function pathOriginatesFromVendor($path)
292+
private function getPathType($path)
254293
{
255294
$realPath = realpath($path);
256295
if (false === $realPath && '-' !== $path && 'Standard input code' !== $path) {
257-
return true;
296+
return self::PATH_TYPE_UNDETERMINED;
258297
}
259298
foreach (self::getVendors() as $vendor) {
260299
if (0 === strpos($realPath, $vendor) && false !== strpbrk(substr($realPath, \strlen($vendor), 1), '/'.\DIRECTORY_SEPARATOR)) {
261-
return true;
300+
return self::PATH_TYPE_VENDOR;
262301
}
263302
}
264303

265-
return false;
304+
foreach (self::$internalPaths as $internalPath) {
305+
if (0 === strpos($realPath, $internalPath)) {
306+
return self::PATH_TYPE_SELF;
307+
}
308+
}
309+
310+
return self::PATH_TYPE_UNDETERMINED;
266311
}
267312

268313
/**
@@ -281,19 +326,4 @@ public function toString()
281326
"\n".str_replace(' '.getcwd().\DIRECTORY_SEPARATOR, ' ', $exception->getTraceAsString()).
282327
"\n";
283328
}
284-
285-
private function getPackageFromLine(array $line)
286-
{
287-
if (!isset($line['file'])) {
288-
return 'internal function';
289-
}
290-
if (!$this->pathOriginatesFromVendor($line['file'])) {
291-
return 'source code';
292-
}
293-
try {
294-
return $this->getPackage($line['file']);
295-
} catch (\RuntimeException $e) {
296-
return 'unknown';
297-
}
298-
}
299329
}

Tests/DeprecationErrorHandler/DeprecationTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public function testItCanDetermineTheClassWhereTheDeprecationHappened()
2727
public function testItCanTellWhetherItIsInternal()
2828
{
2929
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
30-
$this->assertTrue($deprecation->isSelf());
30+
$this->assertSame(Deprecation::TYPE_SELF, $deprecation->getType());
3131
}
3232

3333
public function testLegacyTestMethodIsDetectedAsSuch()
@@ -46,7 +46,7 @@ public function testItCanBeConvertedToAString()
4646
public function testItRulesOutFilesOutsideVendorsAsIndirect()
4747
{
4848
$deprecation = new Deprecation('💩', $this->debugBacktrace(), __FILE__);
49-
$this->assertFalse($deprecation->isIndirect());
49+
$this->assertNotSame(Deprecation::TYPE_INDIRECT, $deprecation->getType());
5050
}
5151

5252
/**

Tests/DeprecationErrorHandler/default.phpt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,13 @@ Unsilenced deprecation notices (3)
7373
1x: unsilenced bar deprecation
7474
1x in FooTestCase::testNonLegacyBar
7575

76-
Remaining self deprecation notices (1)
77-
78-
1x: silenced bar deprecation
79-
1x in FooTestCase::testNonLegacyBar
80-
8176
Legacy deprecation notices (1)
8277

83-
Other deprecation notices (1)
78+
Other deprecation notices (2)
8479

8580
1x: root deprecation
8681

82+
1x: silenced bar deprecation
83+
1x in FooTestCase::testNonLegacyBar
84+
8785
I get precedence over any exit statements inside the deprecation error handler.

Tests/DeprecationErrorHandler/disabled.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
--TEST--
2-
Test DeprecationErrorHandler in weak mode
2+
Test DeprecationErrorHandler in disabled mode
33
--FILE--
44
<?php
55

6-
putenv('SYMFONY_DEPRECATIONS_HELPER=disabled');
6+
$_SERVER['SYMFONY_DEPRECATIONS_HELPER'] = 'disabled';
77
putenv('ANSICON');
88
putenv('ConEmuANSI');
99
putenv('TERM');
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Test DeprecationErrorHandler in disabled mode (via putenv)
3+
--FILE--
4+
<?php
5+
6+
$_ENV['SYMFONY_DEPRECATIONS_HELPER'] = 'disabled';
7+
putenv('ANSICON');
8+
putenv('ConEmuANSI');
9+
putenv('TERM');
10+
11+
$vendor = __DIR__;
12+
while (!file_exists($vendor.'/vendor')) {
13+
$vendor = dirname($vendor);
14+
}
15+
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
16+
require PHPUNIT_COMPOSER_INSTALL;
17+
require_once __DIR__.'/../../bootstrap.php';
18+
19+
echo (int) set_error_handler('var_dump');
20+
echo (int) class_exists('Symfony\Bridge\PhpUnit\DeprecationErrorHandler', false);
21+
22+
?>
23+
--EXPECTF--
24+
00
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Test DeprecationErrorHandler in disabled mode (via putenv)
3+
--FILE--
4+
<?php
5+
6+
putenv('SYMFONY_DEPRECATIONS_HELPER=disabled');
7+
putenv('ANSICON');
8+
putenv('ConEmuANSI');
9+
putenv('TERM');
10+
11+
$vendor = __DIR__;
12+
while (!file_exists($vendor.'/vendor')) {
13+
$vendor = dirname($vendor);
14+
}
15+
define('PHPUNIT_COMPOSER_INSTALL', $vendor.'/vendor/autoload.php');
16+
require PHPUNIT_COMPOSER_INSTALL;
17+
require_once __DIR__.'/../../bootstrap.php';
18+
19+
echo (int) set_error_handler('var_dump');
20+
echo (int) class_exists('Symfony\Bridge\PhpUnit\DeprecationErrorHandler', false);
21+
22+
?>
23+
--EXPECTF--
24+
00
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
<?php
22

33
require_once __DIR__.'/composer/autoload_real.php';
4+
5+
return ComposerAutoloaderInitFake::getLoader();
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
<?php
22

3+
class ComposerLoaderFake
4+
{
5+
public function getPrefixes()
6+
{
7+
return [];
8+
}
9+
10+
public function getPrefixesPsr4()
11+
{
12+
return [];
13+
}
14+
}
15+
316
class ComposerAutoloaderInitFake
417
{
18+
public static function getLoader()
19+
{
20+
return new ComposerLoaderFake();
21+
}
522
}

Tests/DeprecationErrorHandler/self_on_non_vendor.phpt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,12 @@ Unsilenced deprecation notices (3)
6161
1x: unsilenced bar deprecation
6262
1x in FooTestCase::testNonLegacyBar
6363

64-
Remaining self deprecation notices (1)
65-
66-
1x: silenced bar deprecation
67-
1x in FooTestCase::testNonLegacyBar
68-
6964
Legacy deprecation notices (1)
7065

71-
Other deprecation notices (1)
66+
Other deprecation notices (2)
7267

7368
1x: root deprecation
7469

70+
1x: silenced bar deprecation
71+
1x in FooTestCase::testNonLegacyBar
72+

0 commit comments

Comments
 (0)