【问题标题】:custom exception not being caught未捕获自定义异常
【发布时间】:2017-05-24 00:22:10
【问题描述】:

有这个自定义异常:

class TokenException extends Exception 
{
    public $token;

    public function __construct($message, $token)
    {
        $this->message = $message;
        $this->token = $token;

        parent::__construct($message, 1);
    }
}

以及使用它的这段代码:

public function visit()
{
    try {

        // validate input token

        // actions

    }
    catch (TokenException $e) {

        logdebug('TokenException'); // logs "TokenException"

        $res['relogin'] = 1;
        $res['error'] = $e->getMessage() . ' token: ' . $token;

    }
    catch (Exception $e) {

        logdebug('Exception'); // logs "Exception"

        $res['error'] = $e->getMessage() . ' token: ' . $token;

    }
    finally {
        $this->output($res);
    }
}

尽管在验证中它抛出了 TokenException:

throw new TokenException('Invalid token. It does not belong to any user', $token);

它跳过 TokenException 捕获并进入 Exception 捕获,显示令牌错误消息。

这里有什么问题?

编辑

这里是更详细的代码。它使用 Codeigniter MVC 模式:

这是涉及的公共 API 的父控制器:

class Apicontroller extends MX_Controller
{

    /**
     * 
     * @var stdClass $user
     */
    protected $user;


    /**
     * Load user model
     */
    public function __construct()
    {
        $this->load->model('users_model', 'users');
    }


    protected function output($data)
    {
        header('Content-Type: application/json');
        header('Access-Control-Allow-Origin: *');
        echo json_encode($data);
    }

    // other code...

}

没有捕获到异常的代码:

require_once __DIR__ . '/Apicontroller.php';
require_once __DIR__ . '/../TokenException.php';


class Apisellercontroller extends Apicontroller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->model('apiseller_model', 'apiseller');
        $this->load->model('log_model', 'logger');
        $this->load->model('alerts_model', 'alerts');
    }

    // inserts/updates data of a visit made by a sales agent to a client from an external app
    public function visit()
    {
        try {

            $res = [];

            // get api token and user
            $user = $this->input->post('user');
            $token = $this->input->post('token');
            $visit = $this->input->post('data');

            $this->validateRequest($user, $token, $visit);

            // Get user by token from the users model
            $this->user = $this->users->getByToken($token);

            $this->apiseller->setUser($this->user);

            $visit['sellers_id'] = $this->apiseller->getSeller()->id;

            // Insert/update
            $this->load->model('visits_model');

            $res['id'] = $this->visits_model->save($visit);

        }
        catch (TokenException $e) {

            $res['relogin'] = 1;
            $res['error'] = $e->getMessage() . ' token: ' . $token . ' user: ' . $user;

        }
        catch (Exception $e) {

            $res['error'] = $e->getMessage() . ' token: ' . $token . ' user: ' . $user;

        }
        finally {
            $this->output($res);
        }
    }

    private function validateRequest($user, $token, $data)
    {
        if (empty($user)) {
            throw new Exception('User id not received');
        }
        if (empty($token)) {
            throw new Exception('Session token not received');
        }
        if (empty($data)) {
            throw new Exception('Request data not available');
        }

        // Check token validity for user
        $this->apiseller->checkTokenValid($user, $token);
    }

    // other methods
}

用于检查令牌有效性的模型(并在它无效时抛出 TokenExcepcion):

require_once __DIR__ . '/Api_model.php';
require_once __DIR__ . '/../modules/api/TokenException.php';

class Apiseller_model extends Api_model
{

    public function checkTokenValid($currentUser, $token)
    {
        $user = $this->getUserByToken($token);
        if (empty($user)) {
            throw new TokenException('User not found for specified token', $token);
        }

        if ($user->name != $currentUser) {
            throw new TokenException("Invalid token. It doesn't match the specified user", $token);
        }
    }

    // other code...

}

【问题讨论】:

  • 它可能不是你想象的那样。尝试记录 get_class($e) 以确保它是 TokenException。
  • @aynber:它打印“异常”。看起来它没有作为 TokenException 抛出。

标签: php codeigniter exception exception-handling codeigniter-3


【解决方案1】:

你试过了吗 parent::__construct($message, 1);作为第一行?如果没有,我知道它会覆盖之前设置的属性...

class TokenException extends Exception 
{
    public $token;

    public function __construct($message, $token)
    {
        parent::__construct($message, 1);
        $this->message = $message;
        $this->token = $token;
    }
}

【讨论】:

  • 我试过你说的。你说得对,我应该首先调用父母的构造。无论如何,它仍然将异常作为 Exception 而不是 TokenException 抛出
  • 命名空间和用途呢?如果 TokenException 在 namescape 中声明,则必须使用“use”将其包含在它所在的位置和抛出的位置
  • 在这种情况下我没有使用命名空间
  • 我试图复制但没有成功。它进入正确的 TokenException。你能显示整个代码吗?只要确保在您的throw new TokenException() 之前没有抛出异常(基本异常)。这将是我在这种行为中看到的唯一原因。
  • 涉及的代码很多,但我添加了最相关的部分。你可以去看看。
【解决方案2】:

抛出的异常显然不是TokenException的实例,所以我建议你应该看一下stacktrace,看看这个异常到底是从哪里来的:

http://php.net/manual/en/exception.gettraceasstring.php

echo $e->getTraceAsString();die;

您还可以检查您的异常是否作为“先前”传递;这意味着它被包装在您代码的其他部分中:

http://php.net/manual/en/exception.getprevious.php

var_dump($e->getPrevious());die;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-12
    • 1970-01-01
    相关资源
    最近更新 更多