【问题标题】:Limit PHP error handler to specific namespace(s)将 PHP 错误处理程序限制为特定命名空间
【发布时间】:2011-08-10 13:40:04
【问题描述】:

PHP 中是否有任何方法可以仅为特定命名空间设置错误处理程序?我正在构建一个小型框架,我希望能够通过设置自定义错误处理程序并抛出异常来尝试捕获其名称空间内的所有错误/警告/通知消息。 在此特定命名空间之外触发的错误应以常规方式运行。

用PHP能做到吗?

谢谢。

【问题讨论】:

  • 我不这么认为:debug_backtrace() 的返回数据中没有关于命名空间的信息(根据这些信息,您可以告诉错误处理程序如何做出反应)。有兴趣看看是否有任何事情发生。

标签: php namespaces error-handling


【解决方案1】:

对于在发布之前没有实际尝试过,提前道歉:

PHP 传递给错误处理方法的第五个(可选)参数(通常被忽略)是一个指向当前 PHP 符号表的数组 $errcontext。我的想法是,如果您可以按照 Rudie 的建议从异常的回溯中提取名称空间,那么也可以以类似的方式从 $errcontext 中提取名称空间信息。如果这是真的,那么你的错误处理程序可以检查它自己的命名空间,如果当前命名空间与错误处理程序所设计的命名空间不匹配,则返回 false。

此外,错误处理程序可以“堆叠”,这意味着至少在原则上(如果我对“挖掘”$errcontext 的建议确实有效)您可以为每个命名空间设置单独的错误处理程序。

我并不是说这种方法比 Josh 和 Rudie 提出的解决方案更“优雅”,但它似乎确实符合您想要做的事情 - 即强加一种错误处理程序的范围限制。

祝你好运!

【讨论】:

  • 谢谢,真的很有帮助。 $errcontext 并不是我所希望的,但我得到了一些好主意。我将在一个对象中定义错误处理程序,该对象具有存储在静态数组中的一组回调函数名称(因为 set_error_handler 只是覆盖了先前定义的函数)。然后我对每个函数使用 call_user_func 并检查返回值。在这些函数中,我将使用 Rudie 和 Josh 的答案结合的想法。实际上很遗憾,没有用于堆叠错误处理程序的本机实现(我知道)。它丑陋,昂贵......它的工作原理。
  • 实际上,set_error_handler() 并没有覆盖之前声明的错误处理程序——它将一个新的错误处理程序推送到“堆栈”上,PHP 解释器在处理一个错误处理程序时首先调用它错误。如果您的新错误处理程序退出,则不会调用堆栈中剩余的错误处理程序(因此就好像您已丢弃它们),但如果您的错误处理程序返回值 false,则调用堆栈中的下一个错误处理程序。 IMO 让 PHP 处理您的“回调函数堆栈”比自己将它们加载到数组中更干净,但当然可以。
【解决方案2】:

用PHP能做到吗?

我会说这很容易做到。在没有实际编写代码的情况下,这就是我要做的:

  1. 创建一个 try/catch 块
  2. 捕获所有异常 (\Exception)
  3. 查找最后调用的类($exception->getTrace() 中的某处)
  4. 该类将在其名称中包含其命名空间:some\name\space\Class
  5. 使用dirname($namespace) 删除类名(在本例中为"Class"
  6. 对结果做任何你喜欢的事情或重新抛出异常:throw $exception;

编辑
甚至闭包也有命名空间:

namespace oele\boele;

$fn = function() {
  throw new \Exception;
};

try {
  $fn();
}
catch ( \Exception $ex ) {
  print_r($ex);
}

$ex->getTrace()[0]['function'] 将是 oele\boele\{closure}

编辑
太糟糕了 trace 数组没有每个元素的键 'namespace'

【讨论】:

  • 我认为操作员在询问 set_error_handler(),因为不必将所有内容都包装在巨大的 try/catch 块中
  • 如果它是一个框架,它的大部分“应该”被包裹在 FrontController 中的一个大的 try/catch 块中...... IMO
  • 是的,我在考虑 set_error_handler() 函数。捕获您自己的自定义异常应该不是问题。
  • 天哪,这是一个糟糕的答案......首先,OP 不是在谈论 try/catch 块。其次,使用回溯... 第三,在 FQ 类名上使用 dirname 是错误的。最后,当您以“这只是一个愚蠢的问题!”开头时,请确保这不仅仅是一个愚蠢的答案!
  • 他不是在谈论 try/catch... 他是在寻求解决方案。通常这不包括答案。回溯有什么问题?有用!?为什么使用 dirname 错误?有用!他问有没有可能。它是。这不是一个好的解决方案,但它是一个答案(而且,我说过:它有效!)
【解决方案3】:

我之前没有尝试过这样做,所以如果这不起作用,我提前道歉(至少它可能会让你思考),但这是我尝试完成的方式:

由于您的命名空间将成为整个更大框架的一部分,因此我将让框架中的所有类扩展一个基类(为此我们称之为 BaseClass)。在该类中,我将创建一个名为 errorHandler() 的方法。在此函数中,您可以为异常处理做任何您想做的事情(甚至可能自己抛出异常)。

现在你有了这个功能,我们必须弄清楚如何调用这个函数。由于命名空间中的所有对象都扩展了 BaseClass,因此它们都可以访问此 errorHandler() 方法。现在在您的代码中,您可以使用普通的 try / catch 块来捕获发生的异常,而不是使用标准的异常模型,而是调用 $this->errorHander()这里的一些参数——可能是你从 catch 语句中得到的异常)。这应该为您提供您期望发生问题的代码部分所需的内容。

我们需要弄清楚的下一部分是处理您不期望的异常以及您计划如何通过此错误处理程序路由这些异常。这个有点棘手,因为这个解决方案依赖于某处的 try/catch 块。由于这是一个框架,我将假设一切都通过 index.php 或其他一些引导文件(如 Zend Framework 等)运行。如果是这种情况,那么我会将您的 try / catch 放在框架开始执行的任何地方。根据您在 catch 块中遇到的异常,您可以决定是否要通过您的 errorHandler() 方法运行它。我必须管理这部分,不知何故感觉有点脏,应该有更好的方法来做到这一点(也许一旦你走得更远,一个更好的解决方案就会出现)。

希望这可以帮助您在流程中走得更远。如果有人知道如何让最后一部分不那么脏,那就太好了。

【讨论】:

    猜你喜欢
    • 2013-06-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    • 2012-04-27
    相关资源
    最近更新 更多