2011-11-21 77 views
1

当我的__autoload()函数加载文件失败时试图实现某种错误处理我偶然发现了这个小小的“怪异”。__autoload无法在静态方法调用中加载类时抛出异常

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

Note: Prior to 5.3.0, exceptions thrown in the __autoload function could not be caught in the catch block and would result in a fatal error. From 5.3.0+ exceptions thrown in the __autoload function can be caught in the catch block, with 1 provision. If throwing a custom exception, then the custom exception class must be available. The __autoload function may be used recursively to autoload the custom exception class.

这对我所考虑的错误处理类型来说是完美的。就像我想让它下面的作品的例子(它抛出一个异常,它抓住了):

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()函数中的每个类,以便能够避免所述致命错误。知道没有Exception被捕获也是有趣的,因为它似乎是在Exception被处理之前发生的致命错误,如果它甚至被抛在第一位。

+0

我认为第一个例子的工作原理是因为你实例化了一个新对象,'__autoload()'触发了一个新的实例,同时在第二个例子中你调用了一个类的静态方法,没有对象被实例化,所以'__autoload ()'不被调用。 – Galled

+0

@Galled如果我添加'echo $ class;'在我的__autoload()函数中。它会输出2次UndefinedClass,验证是否调用了__autoload(),但在第二种情况下不引发Exception。 – Willem

+0

你得到的致命错误是什么? – Galled

回答

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。

+0

这看起来对我来说真的很不好,如果你的项目跨越了几十个类,那么在自动加载器中进行评估将会严重影响应用程序的性能。我建议找一种方法来最小化或消除静态方法的使用。那,或者只是放弃你的自动加载器的异常。无论如何,我不认为这是建议的。 – GordonM

+0

Willem,请问您是否真的损害了应用程序的性能?我不这么认为,因为eval()只会偶尔被调用...我仍然认为这是一个非常糟糕的黑客攻击,但似乎没有其他选择... –

+0

@Lex虽然我没有真正测试过这个实现的性能影响,我怀疑它会对性能产生影响,只有在出于某种原因,应用程序的php文件被泄露时才会发生eval +异常抛出,这种情况不应该发生。这个实现仅仅是一个安全网络 - 极少数情况下允许你的应用程序在你的用户眼中优雅地“死亡”。不,我还没有找到一个可行的替代方案。 – Willem

相关问题