当在静态方法调用中加载类失败时,__autolload无法抛出异常


__autoload fails to throw an Exception when it fails to load a class on a static method call

当我试图实现某种错误处理时,当我的__autolload()函数加载文件失败时,我偶然发现了这个小'奇怪'。

根据http://nl.php.net/autoload,从PHP 5.3+版本开始,__autolload()函数中抛出的异常可以在catch块中捕获。

注意:在5.3.0之前,在__autolload函数中抛出的异常无法在catch块中捕获,并且会导致致命错误。从5.3.0+开始,在__autolload函数中抛出的异常可以在catch块中捕获,只需要一个规定。如果抛出自定义异常,则自定义异常类必须可用。可以递归地使用__autolload函数来自动加载自定义异常类。

这对于我所想到的错误处理类型非常有效。下面的例子就像我想要的那样工作(它抛出一个异常并被捕获):

function __autoload($class) {
    throw new Exception();
}
try {
    new UndefinedClass();
}
catch (Exception $e) {
    echo 'damnit, it no work!';
}

输出: damn, it no work!

但是,如果我尝试从未定义的类调用静态方法的相同概念,则不会抛出异常,而是会得到一个致命错误。

try {
    $a = UndefinedClass::someRandomStaticMethod();
}
catch (Exception $e) {
    echo 'meh, it no work!';
}
输出:

致命错误:无法找到类"UndefinedClass"在 * * * * * 16行

上面的代码不能工作。没有抛出异常。(使用相同的__autolload()函数)。

http://nl.php.net/autoload没有提到这个用例,这让我想知道我是否在这里做了什么可怕的错误?我如何使我的__autolload()函数在不存在的类的静态方法调用上抛出异常?

如果__autolload()函数根本不可能,spl_autolload()是否允许这种异常抛出?


@Galled

根据您提供的链接,我将__autolload()函数更改为:

function __autoload($class) {
    eval('
            class ' . $class . ' {
            };
        ');
    throw new Exception('Im an Exception!');
}

使用这个版本,所讨论的致命错误不再被馈送到我的监视器。但是,它现在会给我一个不同的致命错误:someRandomStaticMethod()不存在。

当然可以在eval()调用中包含方法的声明。但这不是可行的解决方案,因为我必须在__autolload()函数中重新声明项目中包含的每个类,以避免上述致命错误。同样有趣的是,没有捕获异常,因为似乎致命错误在处理异常之前就发生了,如果它被首先抛出的话。

通过扩展Galled的建议,我多少设法解决了这个问题。在进一步阅读之后,特别是在这里:http://nl.php.net/manual/en/function.spl-autoload-register.php#84086我写了以下内容:

function __autoload($class) {
    ...
    /* if something and/or everything fails */
    eval('
            class ' . $class . ' {
                public function __construct() {
                    throw new Exception(''Im an Exception!'');
                }
                public static function __callstatic($method, $arguments) {
                    throw new Exception(''Im an Exception!'');
                }
            };
        ');
}

这个变化现在将在两个用例上抛出Exceptions。不管类中是否存在方法

虽然上面的工作,我希望有人能提供一个不触及eval()功能的解决方案。因为,出于某种原因,我觉得我刚刚调戏了PHP。