自定义错误处理程序,用于处理对象代码内外的错误

Joc*_*lyn 1 php oop error-handling procedural-programming

我知道Stackoverflow上有很多与自定义错误处理程序相关的问题.但是,在阅读了其中许多内容以及PHP手册之后,我仍然无法解决我的问题.因此我发布了这个问题.

我的脚本目前以这种方式构建:

require 'file.php';
require 'anotherFile.php';
// several more "require" here. These files contain many functions

function myErrorHandler($errno, $errstr, $errfile, $errline, $errcontext){
    // some code to handle errors here

}

class myObject {
    function __construct() {
        // set the values here
    }

    function computeSomething() {
        ...
        doFunction2();
        ...
    }

    function SomethingBadHappened()
    {
    }
}

function doFunction1() {
    // for some reason, an error happens here
    // it is properly handled by the current error handler
}

function doFunction2() {
    // for some reason, an error happens here
    // since it got called by $obj, I want the error handler to run $obj->SomethingBadHappened();
    // but $obj is not known in myErrorHandler function!
}

set_error_handler('myErrorHandler');

// some procedural code here
doFunction1();
doAnotherThing();

// then I use objects
$obj = new myObject();
$obj->run();

// then I may use procedural code again
doSomethingElse();
Run Code Online (Sandbox Code Playgroud)

我的自定义错误处理程序已经正常工作 它捕获并处理在设置错误处理程序后执行的代码中发生的所有PHP错误.

我的问题:

如果在myObject类的方法中发生错误,我想调用非静态方法:

$obj->SomethingBadHappened();
Run Code Online (Sandbox Code Playgroud)

$obj不在范围内myErrorHandler.如何$obj在错误处理程序内部访问以调用成员函数$obj?
我目前有300KB的PHP代码,我无法更改所有函数的签名$obj作为参数添加(功能太多了!).

我读到可以将自定义错误处理程序定义为对象的方法.但是,如果我这样做,它将无法捕获在创建myObject($ obj)实例之前发生的错误.

我也读过关于异常的内容,但它似乎没有帮助解决我的问题.我不愿意使用全局变量.这里有两个问题可以解释为什么应该避免全局变量:

Ter*_*ryE 5

一个有趣的Q,似乎没有人想跳,所以我会给你我的2cents价值,一切都由IMO资格...

错误处理是整齐地处理错误,最终以某种形式的用户友好方式向最终用户报告,以及可能为应用程序支持放置内部取证.一般来说,它应该尝试暴露或解释应用程序上下文 - 太难以及其特定的上下文特定,因此您最终会打开一堆蠕虫.

如果您想在上下文中按层次结构处理错误,那么您现在已经真正进入了异常和异常处理的世界,这是一个完全不同的运行时模型.在这里你可以捕获 - 原则上 - 处理应用程序异常并保留对象上下文,但这可能证明难以实现,我不能想到任何有用的标准模式.

如果$obj是单身人士(并且你愿意考虑使用单身人士模板)那么这将允许你做你想要的.

另一方面,如果你想要的只是一些有限的上下文,例如"处理客户记录XXXX",那么为什么不使用处理程序的静态方法将错误处理程序封装在类中,并使用另一种注册方法来注册假定的上下文,甚至注册回调,这将允许您注册特定于对象的方法来提供此上下文?当然,您需要非常小心地使用类/对象函数来验证任何已注册的回调仍然在有效范围内,以避免潜在的嵌套错误,但是这种框架可以变得可行.

在Jocelyn的反馈之后的脚注

我理解pro和con Singletons的论点,这就是为什么我不自己使用它们并且在最初的答案中也弃用了它们.但是,它们在使用时确实提供了一些优势,这就是为什么某些最佳应用程序(如MediaWiki引擎)仍在使用它们.PHP范围的约束仍然存在.$someObject->method()要从另一个类或函数调用,它必须在调用函数的范围内.没有办法解决这个问题.所以你有一些选择:

  • 如果someClass在任何时候只有一个活动对象,那么你可以通过许多方法将它放在全局范围内,最简单的方法是将对象复制到某个全局变量,或者使用静态方法返回它(所有这些someClass::get()无论如何,经典的单例方法都可以.

  • 另一方面,如果你有多个可以推定在范围内的对象,那么你可以将对象作为参数传递,但绝对不需要这样做.您可以使用push方法将错误处理程序注册到这些方法.一个示例实现是使用4个静态方法和静态私有变量创建和错误处理程序类:

    • myErrorHandler().您描述的错误处理程序,但现在是一个静态类方法.

    • initErrorHandler().你调用它来注册上面的静态方法.

    • registerClassCallback($ callback),其中$ callback是一个标准array($obj,'method')参数.

    • unregisterClassCallback($ callback),其中$ callback是相同的array($obj,'method')参数.

    • $ registeredCallbacks.registerClassCallback()添加和unregisterClassCallback()删除的已注册回调的私有数组.myErrorHandler()可以简单地对此进行操作,class_exists()并method_exists()在调用之前验证每个已注册的回调是否仍然在范围内.

这将做你想要的.请记住,在php中,对变量的对象赋值实际上是对象的句柄.您可以将对象(句柄)复制到任何变量上下文.这不会复制或深层复制基础对象.它实际上是一个引用(虽然在巧妙的语义上与真正的PHP对象引用略有不同 - 但这是一个不同的问答).