Php 捕获异常时的请求状态

Php 捕获异常时的请求状态,php,slim,Php,Slim,我有一个带有自定义errorHandler的Slim框架应用程序和一个小型中间件堆栈。我的中间件将属性添加到请求对象,我希望在发生异常时可以从错误处理程序访问该对象。例如: $app->get('/endpoint', function($request $response, $args) { $myAttribute = $request->getAttribute('myAttribute'); //returns 'myValue' throw new \Exc

我有一个带有自定义errorHandler的Slim框架应用程序和一个小型中间件堆栈。我的中间件将属性添加到请求对象,我希望在发生异常时可以从错误处理程序访问该对象。例如:

$app->get('/endpoint', function($request $response, $args) {
    $myAttribute = $request->getAttribute('myAttribute'); //returns 'myValue'
    throw new \Exception(); //any code that throws an error
})->add(function($request, $response, $next) {
    $request = $request->withAttribute('myAttribute', 'myValue');
    $response = $next($request, $response);
    return $response;
});

$app->getContainer['errorHandler'] = function($c) {
    return function($request, $response, $exception) {
        $myAttribute = $request->getAttribute('myAttribute'); //returns null
        return $response;
    }
};

错误处理程序内的请求对象中不存在该属性,因为在遍历中间件堆栈后,路由内克隆的请求尚未返回在引发异常时(在位置中),是否可以访问请求和响应对象,因为它们存在?我无法显式地传递它们(例如SlimException),因为我试图处理意外错误。

我创建了两个,有点粗糙,引发异常时捕获请求和响应状态的解决方案。这两种方法都试图在尽可能靠近中间件堆栈中心的位置插入try/catch(无需重复代码),并涉及将原始异常与修改的端点参数一起包装到新的异常类中

中间件 只要注意中间件的添加顺序,这种方法就可以工作。不幸的是,它确实需要将最内层的中间件添加到每个路由中,或者至少在中间件修改请求和/或响应对象之前添加。这不会捕获内部或路由之后对请求/响应所做的任何更改

class WrappedException扩展\Exception{
公共资金例外;
公帑申请;
公众反应;
公共函数构造($exception、$request、$response){
$this->exception=$exception;
$this->request=$request;
$this->response=$response;
}
}
$app->get('/endpoint',函数($request$response,$args){
抛出new\Exception();//抛出错误的任何代码
})->添加(函数($request、$response、$next){
试一试{
$response=$next($request,$response);
}catch(\Exception$Exception){
抛出新的WrappedException($exception、$request、$response);
}
返回$response;
});
$app->add(函数($request、$response、$next){
$request=$request->withAttribute('myAttribute','myValue');
$response=$next($request,$response);
返回$response;
});
$app->getContainer['errorHandler']=函数($c){
返回函数($request、$response、$exception){
if($WrappedException的异常实例){
//返回“myValue”
$myAttribute=$exception->request->getAttribute('myAttribute');
}
返回$response;
}
};
路线等级 这会将所有路由包装在一个try块中,并使路由代码更简洁,但必须确保从RouteBase类扩展所有路由

class WrappedException扩展\Exception{
公共资金例外;
公帑申请;
公众反应;
公共函数构造($exception,$request=null,$response=null){
$this->exception=$exception;
$this->request=$request;
$this->response=$response;
}
}
类路由基{
公共函数调用($method,$arguments){
如果(方法_存在($this$method)){
试一试{
$this::$method(…$arguments);
}捕获(\异常$e){
抛出新的WrappedException($e,…$arguments);
}
}否则{
抛出新\异常('未找到路由方法');
}
}
}
类RouteClass扩展了RouteBase{
//受保护--必须可由父类调用,但不能在类外部调用
受保护的函数get(请求$Request,响应$Response,$args){
抛出new\Exception('A new Exception!');
$response->write('hey');
返回$response;
}
}
$app->get('/endpoint',RouteClass:get');
$app->add(函数($request、$response、$next){
$request=$request->withAttribute('myAttribute','myValue');
$response=$next($request,$response);
返回$response;
});
$app->getContainer['errorHandler']=函数($c){
返回函数($request、$response、$exception){
if($WrappedException的异常实例){
//返回“myValue”
$myAttribute=$exception->request->getAttribute('myAttribute');
}
返回$response;
}
};

我想您可以访问$\u请求超全局。答案可能是,不,您不可能轻松做到这一点。请注意,
withAttribute()
用于注入属性,如中所述。您的示例中的
myAttribute
是否符合该描述?如果是这样,可能有一个解决问题的方法,如果不是,你可能需要避免使用<代码>属性(< /代码>),并考虑一个更好的方法。@仁摩,虽然不是唯一的例子,但我主要是尝试获得各种OAuthAtvices属性,如本文所述:消息对象是不可变的,对它们的每次修改都会导致创建一个新的消息对象,这就是为什么您必须显式地覆盖对象,如
$request=$request->withAttri…
,并将修改后的版本传递给下一个中间件,因此不清楚它们是如何存在的。实际上,您可以显式地传递它们,我说您应该这样做,因为这些数据与这个特定的异常相关,而不是所有其他数据。您不必以相同的方式处理所有错误,不同的异常可以以不同的方式处理,因此不必担心其他类型的意外错误。@Nima,我理解这个概念,我正在将“新”请求对象传递给中间件的每一层。但是,当抛出异常时,它会被抛出,并且“新”对象不会自动返回到该点。触发try块时,对请求和响应对象的任何“更改”都将被忽略,因为它们位于完全不同的范围内,不会自动捕获或传递到任何地方。