为什么我收到PHP致命错误:未捕获错误:找不到类'MyClass'?

Jef*_*ett 6 php oop dependency-injection namespaces autoloader

这有效:

class MyClass {
    public $prop = 'hi';
}

class Container {
    static protected $registry = [];
    public static function get($key){
        if(!array_key_exists($key, static::$registry)){
            static::$registry[$key] = new $key;
        }
        return static::$registry[$key];
    }
}

$obj = Container::get('MyClass');
echo $obj->prop;
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试将其分解为单个文件时,我收到错误.

PHP致命错误:未捕获错误:在/nstest/src/Container.php:9中找不到类'MyClass'

这是第9行:

static::$registry[$key] = new $key;
Run Code Online (Sandbox Code Playgroud)

令人抓狂的是我可以对其进行硬编码,并且它可以工作,所以我知道命名空间是正确的.

static::$registry[$key] = new MyClass;
Run Code Online (Sandbox Code Playgroud)

显然我不想硬编码,因为我需要动态值.我也尝试过:

$key = $key::class;
static::$registry[$key] = new $key;
Run Code Online (Sandbox Code Playgroud)

但这给了我这个错误:

PHP致命错误:在compile-time :: class fetch中不允许使用动态类名

我不知所措.克隆这些文件以重现:

.
??? composer.json
??? main.php
??? src
?   ??? Container.php
?   ??? MyClass.php
??? vendor
?   ??? ...
??? works.php
Run Code Online (Sandbox Code Playgroud)

不要忘记自动加载器.

composer dumpautoload
Run Code Online (Sandbox Code Playgroud)

composer.json

{
    "autoload": {
        "psr-4": {
            "scratchers\\nstest\\": "src/"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

main.php

require __DIR__.'/vendor/autoload.php';
use scratchers\nstest\Container;

$obj = Container::get('MyClass');
echo $obj->prop;
Run Code Online (Sandbox Code Playgroud)

SRC/Container.php

namespace scratchers\nstest;

class Container {
    static protected $registry = [];
    public static function get($key){
        if(!array_key_exists($key, static::$registry)){
            static::$registry[$key] = new $key;
        }
        return static::$registry[$key];
    }
}
Run Code Online (Sandbox Code Playgroud)

SRC/MyClass.php

namespace scratchers\nstest;

class MyClass {
    public $prop = 'hi';
}
Run Code Online (Sandbox Code Playgroud)

Jef*_*ett 10

感谢@tkausl,通过将完全限定名称作为变量传递,我能够绕过动态相对命名空间.

require __DIR__.'/vendor/autoload.php';
use scratchers\nstest\Container;
use scratchers\nstest\MyClass;

$obj = Container::get(MyClass::class);
echo $obj->prop;
Run Code Online (Sandbox Code Playgroud)