将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();
无论应用程序是在与顶级命名空间同名的目录中,还是在其他任何地方,此解决方案都有效!
1条答案
按热度按时间ecbunoof1#
您可能需要通读有关autoloading和namespaces的手册页,以确保理解关键概念。
您已经在命名空间
App\Classes
中声明了一个名为MyClass
的类;这意味着它的 * 完全限定 * 名称是App\Classes\MyClass
--这是在该名称空间之外调用它时需要使用的名称。可能同时存在一个 different 类,其完全限定名称仅为MyClass
,因为它不在任何名称空间中,以及其他名称空间中的任意数量的其他类,如App\Security\MyClass
、App\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
)