18
18
*/
19
19
class Deprecation
20
20
{
21
+ private const PATH_TYPE_VENDOR = 'path_type_vendor ' ;
22
+ private const PATH_TYPE_SELF = 'path_type_internal ' ;
23
+ private const PATH_TYPE_UNDETERMINED = 'path_type_undetermined ' ;
24
+
25
+ public const TYPE_SELF = 'type_self ' ;
26
+ public const TYPE_DIRECT = 'type_direct ' ;
27
+ public const TYPE_INDIRECT = 'type_indirect ' ;
28
+ public const TYPE_UNDETERMINED = 'type_undetermined ' ;
29
+
21
30
/**
22
31
* @var array
23
32
*/
@@ -39,13 +48,21 @@ class Deprecation
39
48
private $ originMethod ;
40
49
41
50
/**
42
- * @var bool
51
+ * @var string one of the PATH_TYPE_* constants
43
52
*/
44
- private $ self ;
53
+ private $ triggeringFilePathType ;
45
54
46
55
/** @var string[] absolute paths to vendor directories */
47
56
private static $ vendors ;
48
57
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
+
49
66
/**
50
67
* @param string $message
51
68
* @param string $file
@@ -59,7 +76,7 @@ public function __construct($message, array $trace, $file)
59
76
// No-op
60
77
}
61
78
$ line = $ trace [$ i ];
62
- $ this ->self = ! $ this ->pathOriginatesFromVendor ($ file );
79
+ $ this ->trigerringFilePathType = $ this ->getPathType ($ file );
63
80
if (isset ($ line ['object ' ]) || isset ($ line ['class ' ])) {
64
81
if (isset ($ line ['class ' ]) && 0 === strpos ($ line ['class ' ], SymfonyTestsListenerFor::class)) {
65
82
$ parsedMsg = unserialize ($ this ->message );
@@ -70,8 +87,9 @@ public function __construct($message, array $trace, $file)
70
87
// \Symfony\Bridge\PhpUnit\Legacy\SymfonyTestsListenerTrait::endTest()
71
88
// then we need to use the serialized information to determine
72
89
// 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
+ }
75
93
76
94
return ;
77
95
}
@@ -101,14 +119,6 @@ public function originatesFromAnObject()
101
119
return isset ($ this ->originClass );
102
120
}
103
121
104
- /**
105
- * @return bool
106
- */
107
- public function isSelf ()
108
- {
109
- return $ this ->self ;
110
- }
111
-
112
122
/**
113
123
* @return string
114
124
*/
@@ -163,10 +173,16 @@ public function isLegacy($utilPrefix)
163
173
* Tells whether both the calling package and the called package are vendor
164
174
* packages.
165
175
*
166
- * @return bool
176
+ * @return string
167
177
*/
168
- public function isIndirect ()
178
+ public function getType ()
169
179
{
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
+ }
170
186
$ erroringFile = $ erroringPackage = null ;
171
187
foreach ($ this ->trace as $ line ) {
172
188
if (\in_array ($ line ['function ' ], ['require ' , 'require_once ' , 'include ' , 'include_once ' ], true )) {
@@ -179,25 +195,28 @@ public function isIndirect()
179
195
if ('- ' === $ file || 'Standard input code ' === $ file || !realpath ($ file )) {
180
196
continue ;
181
197
}
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 ;
184
203
}
185
204
if (null !== $ erroringFile && null !== $ erroringPackage ) {
186
205
$ package = $ this ->getPackage ($ file );
187
206
if ('composer ' !== $ package && $ package !== $ erroringPackage ) {
188
- return true ;
207
+ return self :: TYPE_INDIRECT ;
189
208
}
190
209
continue ;
191
210
}
192
211
$ erroringFile = $ file ;
193
212
$ erroringPackage = $ this ->getPackage ($ file );
194
213
}
195
214
196
- return false ;
215
+ return self :: TYPE_DIRECT ;
197
216
}
198
217
199
218
/**
200
- * pathOriginatesFromVendor () should always be called prior to calling this method.
219
+ * getPathType () should always be called prior to calling this method.
201
220
*
202
221
* @param string $path
203
222
*
@@ -237,6 +256,15 @@ private static function getVendors()
237
256
$ v = \dirname (\dirname ($ r ->getFileName ()));
238
257
if (file_exists ($ v .'/composer/installed.json ' )) {
239
258
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 ;
240
268
}
241
269
}
242
270
}
@@ -245,24 +273,41 @@ private static function getVendors()
245
273
return self ::$ vendors ;
246
274
}
247
275
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
+
248
287
/**
249
288
* @param string $path
250
289
*
251
- * @return bool
290
+ * @return string
252
291
*/
253
- private function pathOriginatesFromVendor ($ path )
292
+ private function getPathType ($ path )
254
293
{
255
294
$ realPath = realpath ($ path );
256
295
if (false === $ realPath && '- ' !== $ path && 'Standard input code ' !== $ path ) {
257
- return true ;
296
+ return self :: PATH_TYPE_UNDETERMINED ;
258
297
}
259
298
foreach (self ::getVendors () as $ vendor ) {
260
299
if (0 === strpos ($ realPath , $ vendor ) && false !== strpbrk (substr ($ realPath , \strlen ($ vendor ), 1 ), '/ ' .\DIRECTORY_SEPARATOR )) {
261
- return true ;
300
+ return self :: PATH_TYPE_VENDOR ;
262
301
}
263
302
}
264
303
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 ;
266
311
}
267
312
268
313
/**
@@ -281,19 +326,4 @@ public function toString()
281
326
"\n" .str_replace (' ' .getcwd ().\DIRECTORY_SEPARATOR , ' ' , $ exception ->getTraceAsString ()).
282
327
"\n" ;
283
328
}
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
- }
299
329
}
0 commit comments