@@ -93,6 +93,12 @@ class Autoloader
9393 */
9494 protected $ helpers = ['url ' ];
9595
96+ /**
97+ * Track whether Composer namespaces have been loaded to prevent
98+ * re-loading in parallel test execution contexts.
99+ */
100+ private bool $ composerNamespacesLoaded = false ;
101+
96102 public function __construct (private readonly string $ composerPath = COMPOSER_PATH )
97103 {
98104 }
@@ -150,9 +156,11 @@ private function loadComposerAutoloader(Modules $modules): void
150156 $ composer = include $ this ->composerPath ;
151157
152158 // Should we load through Composer's namespaces, also?
153- if ($ modules ->discoverInComposer ) {
159+ // Guard against repeated loading in parallel execution environments
160+ if ($ modules ->discoverInComposer && ! $ this ->composerNamespacesLoaded ) {
154161 $ composerPackages = $ modules ->composerPackages ;
155162 $ this ->loadComposerNamespaces ($ composer , $ composerPackages ?? []);
163+ $ this ->composerNamespacesLoaded = true ;
156164 }
157165
158166 unset($ composer );
@@ -371,6 +379,24 @@ public function sanitizeFilename(string $filename): string
371379 return $ cleanFilename ;
372380 }
373381
382+ /**
383+ * Convert a path to absolute path if it isn't already.
384+ * Prevents issues with relative paths in parallel execution.
385+ */
386+ private function makePathAbsolute (string $ path ): string
387+ {
388+ if (str_starts_with ($ path , '/ ' ) || (strlen ($ path ) > 1 && $ path [1 ] === ': ' )) {
389+ return $ path ; // Already absolute
390+ }
391+
392+ // Make relative to vendor directory
393+ if (defined ('VENDORPATH ' )) {
394+ return VENDORPATH . ltrim ($ path , '/ \\' );
395+ }
396+
397+ return $ path ;
398+ }
399+
374400 /**
375401 * @param array{only?: list<string>, exclude?: list<string>} $composerPackages
376402 */
@@ -441,7 +467,8 @@ private function loadComposerNamespaces(ClassLoader $composer, array $composerPa
441467
442468 if ($ add ) {
443469 // Composer stores namespaces with trailing slash. We don't.
444- $ newPaths [rtrim ($ namespace , '\\ ' )] = $ srcPaths ;
470+ // Ensure all paths are absolute to prevent issues in parallel execution
471+ $ newPaths [rtrim ($ namespace , '\\ ' )] = array_map ($ this ->makePathAbsolute (...), $ srcPaths );
445472 }
446473 }
447474
0 commit comments