php 使用命名空间自动加载-致命错误:未捕获的错误:未找到类"MyClass"

doinxwow  于 2023-02-07  发布在  PHP
关注(0)|答案(1)|浏览(177)

将spl_autoload_register()与使用命名空间的类一起使用时,会出现以下错误消息:* 致命错误:未捕获的错误:未找到类"MyClass"... *
在出现此错误消息之前,自动加载程序会回显"... MyClass.php IS found"。
使用两个文件:"/index.php "(在根目录中)和"/classes/我的类。
Index.php:

declare(strict_types=1);

define ('ROOT_DIR', __DIR__ . '/');
define ('CLASS_DIR', ROOT_DIR . 'classes/');

spl_autoload_register(function($class) {
    $filepath = CLASS_DIR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
    if (file_exists($filepath)) {
        require_once $filepath;
        echo('<br /><b>' . $filepath . '</b> IS found.<br />');
    } else {
        echo('<br /><b>' . $filepath . '</b> not found.<br />');
        exit;
    }
});

$myclass = new MyClass();

MyClass.php:

declare(strict_types=1);

namespace App\Classes

class MyClass
{
    // ...
}

有人知道怎么解决吗?
根据https://www.php-fig.org/psr/psr-4/,供应商名称是必需的,因此我使用"App"作为顶级名称空间名称,尽管它不是目录(因为我的网站使用服务器的根目录)。
我还尝试过在index.php的"$myclass = new myclass()"之前添加"use App/classes/Myclass",但这会导致更多的问题,因为自动加载器会查找目录"/classes/App/Classes "...
从类中删除了名称空间之后,一切都很好,我可以通过$myclass使用类的函数。但是我想开始使用名称空间...任何帮助都将非常感谢!〈3

    • 结论**:应使用行"$myclass = new App\Classes\MyClass();"或"use App\Classes\MyClass;"。

因此,在使用这个自动加载函数时,不可能同时使用服务器的根目录和顶级命名空间名称("App")。该函数必须扩展以允许这种可能性。并且"classes"目录将被重命名为"Classes"。当它准备好时,我将发布我的解决方案!
欲了解更多细节,请阅读下面的评论由@IMSoP回答(非常感谢您的帮助!)

    • 溶液**:
declare(strict_types=1);

namespace App;

define ('ROOT_DIR', $_SERVER['DOCUMENT_ROOT'] . '/');
define ('BASE_DIR', __DIR__ . '/');
define ('TOP_LEVEL_NAMESPACE_NAME', __NAMESPACE__ . '/');

spl_autoload_register(function($class) {
    if (BASE_DIR == ROOT_DIR . TOP_LEVEL_NAMESPACE_NAME) {
        $filepath = ROOT_DIR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
    } else {
        $filepath = BASE_DIR . str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
        $filepath = str_replace(TOP_LEVEL_NAMESPACE_NAME, '', $filepath);
    }
    if (file_exists($filepath)) {
        require_once $filepath;
    } else {
        echo('Class <b>' . end(explode('\\', $class)) . '.php</b> was not found.');
        exit;
    }
});

use App\Classes\MyClass;

$myclass = new MyClass();

无论应用程序是在与顶级命名空间同名的目录中,还是在其他任何地方,此解决方案都有效!

ecbunoof

ecbunoof1#

您可能需要通读有关autoloadingnamespaces的手册页,以确保理解关键概念。
您已经在命名空间App\Classes中声明了一个名为MyClass的类;这意味着它的 * 完全限定 * 名称是App\Classes\MyClass--这是在该名称空间之外调用它时需要使用的名称。可能同时存在一个 different 类,其完全限定名称仅为MyClass,因为它不在任何名称空间中,以及其他名称空间中的任意数量的其他类,如App\Security\MyClassApp\UI\MyClass等。
然后你试图引用index.php中一个名为MyClass的类,这个类触发了autoloader,autoloader将它翻译成.../classes/MyClass.php这样的路径,并加载正确的 file;但是那个文件定义了 * 你的命名空间类 。所以在自动加载器完成之后, 没有名为MyClass的类,只有App\Classes\MyClass *,代码失败。
如果你写new App\Classes\MyClass,你会得到 * 相反 * 的问题:传递给autoloader的字符串是'App\Classes\MyClass',您可以将其转换为'.../classes/App/Classes/MyClass.php'这样的文件路径-但 * 这不是您的文件所在的位置 *(添加use App\ClassesMyClass的作用是相同的-use语句只是帮助编译器避免经常写出完全限定的名称)。
您需要做的是 both

  • 始终使用完全限定的类名(或使用别名use
  • 对文件进行布局以匹配名称空间结构,以便自动加载程序可以找到它们,这通常意味着每个名称空间对应一个目录

相关问题