PHP - 防止自动加载器错误

时间:2015-03-24 08:10:24

标签: php oop autoload spl-autoload-register

我的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调用之前,我无法找到检查类是否可以自动加载的方法。

4 个答案:

答案 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}();