4848 */
4949class AutoloadSourceLocator extends AbstractSourceLocator
5050{
51+ private const DEFAULT_STREAM_WRAPPER_PROTOCOLS = [
52+ 'file ' ,
53+ 'phar ' ,
54+ ];
55+
5156 /** @var AstLocator */
5257 private $ astLocator ;
5358
@@ -60,21 +65,27 @@ class AutoloadSourceLocator extends AbstractSourceLocator
6065 /** @var NodeVisitorAbstract */
6166 private $ constantVisitor ;
6267
68+ /** @var string[] */
69+ private $ streamWrapperProtocols ;
70+
6371 /**
6472 * Note: the constructor has been made a 0-argument constructor because `\stream_wrapper_register`
6573 * is a piece of trash, and doesn't accept instances, just class names.
74+ *
75+ * @param string[] $streamWrapperProtocols
6676 */
67- public function __construct (?AstLocator $ astLocator = null , ?Parser $ phpParser = null )
77+ public function __construct (?AstLocator $ astLocator = null , ?Parser $ phpParser = null , array $ streamWrapperProtocols = self :: DEFAULT_STREAM_WRAPPER_PROTOCOLS )
6878 {
6979 $ betterReflection = new BetterReflection ();
7080
7181 $ validLocator = $ astLocator ?? self ::$ currentAstLocator ?? $ betterReflection ->astLocator ();
7282
7383 parent ::__construct ($ validLocator );
7484
75- $ this ->astLocator = $ validLocator ;
76- $ this ->phpParser = $ phpParser ?? $ betterReflection ->phpParser ();
77- $ this ->constantVisitor = $ this ->createConstantVisitor ();
85+ $ this ->astLocator = $ validLocator ;
86+ $ this ->phpParser = $ phpParser ?? $ betterReflection ->phpParser ();
87+ $ this ->streamWrapperProtocols = $ streamWrapperProtocols ;
88+ $ this ->constantVisitor = $ this ->createConstantVisitor ();
7889
7990 $ this ->nodeTraverser = new NodeTraverser ();
8091 $ this ->nodeTraverser ->addVisitor (new NameResolver ());
@@ -163,18 +174,34 @@ private function locateClassByName(string $className) : ?string
163174
164175 self ::$ autoloadLocatedFile = null ;
165176 self ::$ currentAstLocator = $ this ->astLocator ; // passing the locator on to the implicitly instantiated `self`
166- $ previousErrorHandler = set_error_handler (static function (int $ errno , string $ errstr ) : bool {
167- return true ;
168- });
169- stream_wrapper_unregister ('file ' );
170- stream_wrapper_register ('file ' , self ::class);
171- class_exists ($ className );
172- stream_wrapper_restore ('file ' );
173- set_error_handler ($ previousErrorHandler );
177+
178+ $ this ->silenceErrors ();
179+
180+ foreach ($ this ->streamWrapperProtocols as $ protocol ) {
181+ stream_wrapper_unregister ($ protocol );
182+ stream_wrapper_register ($ protocol , self ::class);
183+ }
184+
185+ try {
186+ class_exists ($ className );
187+ } finally {
188+ foreach ($ this ->streamWrapperProtocols as $ protocol ) {
189+ stream_wrapper_restore ($ protocol );
190+ }
191+
192+ restore_error_handler ();
193+ }
174194
175195 return self ::$ autoloadLocatedFile ;
176196 }
177197
198+ private function silenceErrors () : void
199+ {
200+ set_error_handler (static function () : bool {
201+ return true ;
202+ });
203+ }
204+
178205 /**
179206 * We can only load functions if they already exist, because PHP does not
180207 * have function autoloading. Therefore if it exists, we simply use the
@@ -275,21 +302,22 @@ public function stream_open($path, $mode, $options, &$opened_path) : bool
275302 */
276303 public function url_stat ($ path , $ flags )
277304 {
278- stream_wrapper_restore ('file ' );
305+ foreach ($ this ->streamWrapperProtocols as $ protocol ) {
306+ stream_wrapper_restore ($ protocol );
307+ }
279308
280309 if ($ flags & STREAM_URL_STAT_QUIET ) {
281- set_error_handler (static function () {
282- // Use native error handler
283- return false ;
284- });
285- $ result = @stat ($ path );
286310 restore_error_handler ();
311+ $ result = @stat ($ path );
312+ $ this ->silenceErrors ();
287313 } else {
288314 $ result = stat ($ path );
289315 }
290316
291- stream_wrapper_unregister ('file ' );
292- stream_wrapper_register ('file ' , self ::class);
317+ foreach ($ this ->streamWrapperProtocols as $ protocol ) {
318+ stream_wrapper_unregister ($ protocol );
319+ stream_wrapper_register ($ protocol , self ::class);
320+ }
293321
294322 return $ result ;
295323 }
0 commit comments