diff --git a/CHANGELOG.md b/CHANGELOG.md index 83d1e2b..f707b94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [GH#185](https://github.com/jolicode/automapper/pull/185) Fix constructor with default parameter array does not work with constructor_arguments context - [GH#187](https://github.com/jolicode/automapper/pull/187) Fix regression after [GH#184](https://github.com/jolicode/automapper/pull/184) - [GH#192](https://github.com/jolicode/automapper/pull/192) Fix source and context not passed to callable transformer +- [GH#197](https://github.com/jolicode/automapper/pull/197) Fix race condition in EvalLoader ## [9.1.2] - 2024-09-03 ### Fixed diff --git a/src/Loader/EvalLoader.php b/src/Loader/EvalLoader.php index 43f9b2c..163499e 100644 --- a/src/Loader/EvalLoader.php +++ b/src/Loader/EvalLoader.php @@ -16,24 +16,40 @@ * * @author Joel Wurtz * - * @internal + * @internal */ -final readonly class EvalLoader implements ClassLoaderInterface +final class EvalLoader implements ClassLoaderInterface { - private PrettyPrinterAbstract $printer; + /** @var array */ + private static array $lockMap = []; public function __construct( - private MapperGenerator $generator, - private MetadataFactory $metadataFactory, + private readonly MapperGenerator $generator, + private readonly MetadataFactory $metadataFactory, + private readonly PrettyPrinterAbstract $printer = new Standard(), ) { - $this->printer = new Standard(); } public function loadClass(MapperMetadata $mapperMetadata): void { - eval($this->printer->prettyPrint($this->generator->generate( - $this->metadataFactory->getGeneratorMetadata($mapperMetadata->source, $mapperMetadata->target) - ))); + if (isset(self::$lockMap[$mapperMetadata->className])) { + do { + usleep(100000); // 0.1 second + } while (isset(self::$lockMap[$mapperMetadata->className])); // @phpstan-ignore isset.offset + + if (class_exists($mapperMetadata->className, false)) { + return; + } + } + + self::$lockMap[$mapperMetadata->className] = true; + try { + eval($this->printer->prettyPrint($this->generator->generate( + $this->metadataFactory->getGeneratorMetadata($mapperMetadata->source, $mapperMetadata->target) + ))); + } finally { + unset(self::$lockMap[$mapperMetadata->className]); + } } public function buildMappers(MetadataRegistry $registry): bool