【问题标题】:__autoload fails to throw an Exception when it fails to load a class on a static method call__autoload 无法在静态方法调用上加载类时抛出异常
【发布时间】:2011-11-21 14:35:13
【问题描述】:

当我的 __autoload() 函数无法加载文件时尝试执行某种错误处理时,我偶然发现了这个小“怪事”。

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

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

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

function __autoload($class) {
    throw new Exception();
}

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

输出:该死,没用!

但是,如果我使用未定义类的静态方法调用尝试相同的概念,则不会引发异常,而是会收到致命错误。

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

输出: 致命错误:在线 ***** 中找不到类“UndefinedClass” 16

上面的代码不起作用。不抛出异常。 (使用相同的 __autoload() 函数)。

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

如果 __autoload() 函数根本无法做到这一点,那么 spl_autoload() 是否允许这种异常抛出?


@Galled

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

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

使用此版本时,我的显示器不再会出现有问题的致命错误。但是,它现在会给我一个不同的致命错误:someRandomStaticMethod() 不存在这一事实。

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

【问题讨论】:

  • 我认为第一个示例有效,因为您实例化了一个新对象,__autoload() 触发了一个新实例,同时在第二个示例中,您正在调用类的静态方法并且没有实例化对象所以__autoload() 不会被调用。
  • @Galled 如果我添加 'echo $class;'在我的 __autoload() 函数中。会输出UndefinedClass 2次,验证调用了__autoload(),但是第二种情况没有抛出异常。
  • 你得到的致命错误是什么?
  • Fatal error: Class 'UndefinedClass' not found in ************* on line 16 使用静态方法调用时。
  • 你复习过this__autoload-exception的方法吗??

标签: php exception autoload


【解决方案1】:

通过扩展 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。

【讨论】:

  • 这对我来说似乎很棘手,如果您的项目跨越几十个左右的类,在自动加载器中使用 eval 真的会损害应用程序的性能。我建议找到一种方法来最小化或消除静态方法的使用。那,或者只是放弃在你的自动加载器中抛出异常。我不认为这是推荐的。
  • Willem,您能否说明一下这是否真的会损害应用程序的性能?我不这么认为,因为 eval() 只会偶尔被调用......我仍然认为这是一个非常糟糕的 hack,但似乎别无选择......
  • @Lex 虽然我还没有实际测试过这个实现的性能影响,但我怀疑它是否会对性能产生影响,只有在由于某种原因 php 文件时才会发生 eval + 异常抛出您的应用程序受到损害,这绝不应该发生。这个实现只是一个安全网,用于允许您的应用程序在用户眼中优雅地“死去”的场合——极其罕见的场合。不,我还没有找到可行的替代方案。
猜你喜欢
  • 2012-11-22
  • 1970-01-01
  • 2017-06-27
  • 2017-05-31
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
  • 1970-01-01
  • 2018-04-08
相关资源
最近更新 更多