【问题标题】:Is it possible in PHP to prevent "Fatal error: Call to undefined function"?PHP中是否可以防止“致命错误:调用未定义函数”?
【发布时间】:2011-10-30 07:51:22
【问题描述】:

在 PHP 中,有什么方法可以让我忽略未定义的函数,而不是抛出在浏览器中可见的致命错误?即,致命错误:调用未定义函数

我知道有将所有自定义函数包装在下面的条件中的做法,但是有没有一种编程方式来获得这种效果?

if (function_exists('my_function')) { 

   // use my_function() here;

}

【问题讨论】:

  • 我很想知道您想要达到的目标。跳过函数时什么可能正常工作?
  • 致@PhilWallach 的评论:“并非所有功能都是平等的”。这完全取决于应用程序域。有些可以做一些可选的事情,比如对一些变量进行非关键的改进。捕捉/跳过 undef。函数与使用方法做同样的事情一样合法。应该只有一个全局 __call 魔术方法。 (注意:“什么时候应该使用 OOP”是一个完全不同的问题,与这里的观点正交。)
  • //跳过函数时什么可能正常工作?// 这是主流编程语言中metaprogramming 的一个众所周知的元素...参见例如: method-missing

标签: php error-handling undefined fatal-error


【解决方案1】:

没有。致命错误是致命的。即使您要编写自己的错误处理程序或使用@ 错误抑制运算符,E_FATAL 错误仍会导致脚本停止执行。

处理这个问题的唯一方法是使用function_exists()(也可能是is_callable()),就像你上面的例子一样。

围绕潜在(可能?)错误进行防御性编码总是比让错误发生并在以后处理它更好的主意。

编辑 - php7 改变了这种行为,未定义的函数/方法是可捕获的异常。

【讨论】:

  • 请参阅stackoverflow.com/questions/277224/… 了解可能的解决方法
  • @ncatnow 我知道register_shutdown_function(),但没有将其包含在我的答案中,因为它似乎与手头的问题无关。该函数不会使致命错误不致命,它只是让应用程序在死前痛苦地尖叫。
  • 当然@AgentConundrum - 我添加了链接,因为我觉得它确实为问题提供了解决方法,特别是“而不是抛出在浏览器中可见的致命错误”,register_shutdown_function() 将允许开发人员对致命错误采取替代措施。
  • 那些寻找类方法的人,见method_exists
  • @AgentConundrum 只是补充一下 PHP 7。我试图使用 ParseErrorException 来捕捉错误,但没有人这样做。但是...使用Throwable 就可以了!谢谢你给我的灵感。
【解决方案2】:

在 php 7 中,这现在是可能的。

示例代码:

try {
    some_undefined_function_or_method();
} catch (\Error $ex) { // Error is the base class for all internal PHP error exceptions.
    var_dump($ex);
}

demo

http://php.net/manual/en/migration70.incompatible.php

许多致命和可恢复的致命错误已在 PHP 7 中转换为异常。这些错误异常继承自 Error 类,该类本身实现 Throwable 接口(所有异常都继承的新基接口)。

【讨论】:

【解决方案3】:

您的要求似乎有点愚蠢,但您可以通过将所有函数声明为类的方法,然后将 __call 实现为该类的方法来处理任何未定义的方法调用,从而获得类似的效果。然后,您可以随意处理对未定义方法的调用。查看文档here

【讨论】:

    【解决方案4】:

    如果您想在处理对象时抑制此错误,请使用此函数:

    function OM($object, $method_to_run, $param){ //Object method
        if(method_exists(get_class($object), $method_to_run)){
            $object->$method_to_run($param);
        }        
    }
    

    问候

    【讨论】:

    • 唯一的缺点是您必须使用选项数组作为方法参数。这意味着方法/对象必须以某种模式设计。 (适用于 __set() 等魔术方法。
    • 几年前我开始使用同样的策略,但我放弃了它,因为它干扰了大多数 IDE 进行静态分析的能力。能够让 IDE 告诉我代码库中调用某个方法的所有位置非常有价值,并且在进行动态方法调用时(就像这个示例所做的那样),它们不能再提供该功能,也不能提供许多其他有用的静态分析功能。
    【解决方案5】:

    我们可以隐藏错误,但这会记录 apache 错误日志

    //设置显示错误为真。

    ini_set('display_errors', "0");
    

    //报告除notice以外的所有错误

    ini_set('error_reporting', E_ALL ^ E_NOTICE ^ E_STRICT);
    

    //我们可以使用try catch方法

    try {
        my_method();
    } catch (\Error $ex) { // Error is the base class for all internal PHP error exceptions.
        var_dump($ex);
    }
    

    //检查方法是否存在

    function_exists()

    【讨论】:

    • 问题是问有没有办法自动实现条件逻辑,单纯隐藏致命错误并不能做到这一点,所有情况下都要避免使用imo。
    【解决方案6】:

    防止没有。但是使用 register_shutdown_function() 捕获并记录是的

    PHP manual

    function shutDown_handler()
    {
       $last_error = error_get_last();
       //verify if shutwown is caused by an error
       if (isset ($last_error['type']) && $last_error['type'] == E_ERROR)
       {
          /*
            my activity for log or messaging
            you can use info: 
              $last_error['type'], $last_error['message'],
              $last_error['file'], $last_error['line']
              see about on the manual PHP at error_get_last()
          */
       }
    }
    
    register_shutdown_function ('shutDown_handler');
    

    【讨论】:

      【解决方案7】:

      我在 PHP 7 中发现 try/catch 适用于“调用未定义函数”错误。捕获的 Exception 对象不是 Throwable 类,也不是 ErrorException 而是 Error。

      catch 接收到的异常对象包含错误消息、文件和行号以及堆栈跟踪,但不包含严重性代码。

      此 catch 允许程序进行自己的日志记录或分析,并从用户可见的输出中隐藏错误消息(但会将错误记录在 PHP 错误日志中),这正是生产网站所需要的。它还允许继续执行,这可能很危险,但您可以简单地放置“exit;”在 catch 代码块的末尾,以防止程序继续运行。

      【讨论】:

      • 捕获的 Exception 对象不是 Throwable 类,也不是 ErrorException 而是 Error。 它抛出一个“Error”异常,它是 Throwable 的子类,符合 PHP7's manual .因此,它不是我们习惯的错误,具有错误级别或严重性,也不是那种错误,例如致命错误或PHP Error Levels 中的错误。
      • 这个 catch 允许 ....(但会在 PHP 错误日志中记录错误),... 不正确,打开你的 php_error.log,抛出并捕获try/catch 中的 Error Exception,并且日志中没有添加任何行。
      猜你喜欢
      • 1970-01-01
      • 2016-02-20
      • 2014-07-21
      • 2016-07-02
      • 1970-01-01
      • 2016-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多