我的php中有一个MVC结构。
我使用自动加载来初始化正确的控制器。
这是我的index.php非常愚蠢的版本:
<?php
spl_autoload_extensions('.class.php');
spl_autoload_register();
$controller = strtolower($_GET["controller"]);
$action = strtolower($_GET["action"]);
$obj = new $controller();
$obj->{$action}();
因此,假设用户加载www.example.com/Page/View
。 Apache会将其重写为www.example.com?controller=Page&action=View
。然后当php调用$obj = new $controller();
时,它会尝试在与文件相同的目录中找到page.class.php
(显然在我的应用程序中,文件结构不是那么简单,有命名空间等等),然后在里面加载Page
类并执行Page->View();
。
现在,假设用户输入拼写错误并尝试加载www.example.com/Pagr/View
。理想情况下,他应该获得404标头响应。但是对于当前的实现,当php无法自动加载Fatal error
时,它只会抛出pagr.class.php
。
如何防止此错误发生?我做了一些研究,在new
调用之前,我无法找到检查类是否可以自动加载的方法。
答案 0 :(得分:4)
在尝试加载类之前,使用class_exists()
检查类是否存在。
但是,我在这里是如何做到的:
class ClassNotFoundException extends Exception {}
function autoloadClass($class) {
$file = $class . '.class.php';
if(!file_exists($file)) {
throw new ClassNotFoundException($class);
}
require($file);
}
spl_autoload_register('autoloadClass');
try {
$obj = new $controller();
}
catch(ClassNotFoundException $e) {
// call 404 page
}
答案 1 :(得分:1)
除非你绝对需要一种方法来检查这个类是否可以自动加载。否则,如果在实例化对象之前需要检查控制器文件是否存在,可以尝试:
if(file_exists(strtolower($controller).'.class.php') && class_exists ($controller, false))
{
$obj = new $controller();
}
传递给class_exists()
的第二个参数确保它不会尝试自动加载该类。我不知道这对你有什么帮助。
答案 2 :(得分:1)
@halloei是正确的,但它需要一个评论来解释为什么它是正确的。 class_exists
是另一个有趣的PHP函数,尝试自动加载类以防它不存在。这是违反直觉的,但这是它的工作原理(这种行为可以通过第二个参数关闭)。因此,class_exists
不会告诉您类是否存在,但是它是否存在或是否已注册自动加载器。
答案 3 :(得分:0)
这是一种方法。
如果尚未定义, class_exists()
可能会尝试自动加载一个类。但是,如果自动加载器出现故障,则当前在php中有一个bug会使class_exists()
抛出LogicException
。但是我们可以简单地捕获这个异常,直到修复bug为止!
<?php
spl_autoload_extensions('.class.php');
spl_autoload_register();
$controller = strtolower($_GET["controller"]);
$action = strtolower($_GET["action"]);
try {
$class_exists = class_exists($controller);
}
catch(LogicException $e) {
$class_exists = false;
}
finally {
if(!$class_exists) {
http_response_code(404);
exit();
}
}
$obj = new $controller();
$obj->{$action}();