diff --git a/UPGRADE.md b/UPGRADE.md
index 0673dc70bf1..24d699e1371 100644
--- a/UPGRADE.md
+++ b/UPGRADE.md
@@ -1,5 +1,9 @@
# Upgrade to 3.0
+## BC BREAK: `Doctrine\ORM\Proxy\Autoloader` no longer extends `Doctrine\Common\Proxy\Autoloader`
+
+Make sure to use the former when writing a type declaration or an `instanceof` check.
+
## Minor BC BREAK: Changed order of arguments passed to `OneToOne`, `ManyToOne` and `Index` mapping PHP attributes
To keep PHP mapping attributes consistent, order of arguments passed to above attributes has been changed
@@ -328,10 +332,6 @@ Use `Doctrine\Persistence\Mapping\Driver\StaticPHPDriver` and
The second argument to `UnderscoreNamingStrategy::__construct()` was dropped,
the strategy can no longer be unaware of numbers.
-## BC BREAK: Remove `Doctrine\ORM\Proxy\Autoloader`
-
-Use `Doctrine\Common\Proxy\Autoloader` instead.
-
## BC BREAK: Remove `Doctrine\ORM\Tools\DisconnectedClassMetadataFactory`
No replacement is provided.
diff --git a/composer.json b/composer.json
index ceae5193171..1064ebadeaf 100644
--- a/composer.json
+++ b/composer.json
@@ -24,7 +24,6 @@
"composer-runtime-api": "^2",
"ext-ctype": "*",
"doctrine/collections": "^2.1",
- "doctrine/common": "^3.3",
"doctrine/dbal": "^3.6 || ^4",
"doctrine/deprecations": "^0.5.3 || ^1",
"doctrine/event-manager": "^1.2 || ^2",
diff --git a/lib/Doctrine/ORM/Proxy/Autoloader.php b/lib/Doctrine/ORM/Proxy/Autoloader.php
new file mode 100644
index 00000000000..d30477a80e8
--- /dev/null
+++ b/lib/Doctrine/ORM/Proxy/Autoloader.php
@@ -0,0 +1,86 @@
+string
+
+
+ $autoloader
+
+
+ $autoloader
+
+
+ Closure(string): void
+
+
+ require $file
+
+
$classMetadata
diff --git a/tests/Doctrine/Tests/Proxy/AutoloaderTest.php b/tests/Doctrine/Tests/Proxy/AutoloaderTest.php
new file mode 100644
index 00000000000..1bcf37910a2
--- /dev/null
+++ b/tests/Doctrine/Tests/Proxy/AutoloaderTest.php
@@ -0,0 +1,57 @@
+ */
+ public static function dataResolveFile(): iterable
+ {
+ return [
+ ['/tmp', 'MyProxy', 'MyProxy\RealClass', '/tmp' . DIRECTORY_SEPARATOR . 'RealClass.php'],
+ ['/tmp', 'MyProxy', 'MyProxy\__CG__\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__RealClass.php'],
+ ['/tmp', 'MyProxy\Subdir', 'MyProxy\Subdir\__CG__\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__RealClass.php'],
+ ['/tmp', 'MyProxy', 'MyProxy\__CG__\Other\RealClass', '/tmp' . DIRECTORY_SEPARATOR . '__CG__OtherRealClass.php'],
+ ];
+ }
+
+ /** @param class-string $className */
+ #[DataProvider('dataResolveFile')]
+ public function testResolveFile(
+ string $proxyDir,
+ string $proxyNamespace,
+ string $className,
+ string $expectedProxyFile,
+ ): void {
+ $actualProxyFile = Autoloader::resolveFile($proxyDir, $proxyNamespace, $className);
+ self::assertEquals($expectedProxyFile, $actualProxyFile);
+ }
+
+ public function testAutoload(): void
+ {
+ if (file_exists(sys_get_temp_dir() . '/AutoloaderTestClass.php')) {
+ unlink(sys_get_temp_dir() . '/AutoloaderTestClass.php');
+ }
+
+ $autoloader = Autoloader::register(sys_get_temp_dir(), 'ProxyAutoloaderTest', static function ($proxyDir, $proxyNamespace, $className): void {
+ file_put_contents(sys_get_temp_dir() . '/AutoloaderTestClass.php', '