背景
ci3.0 框架核心代码自动实现了异常,并实现了抛出的对应页面和方法,对于一些个性化需求特别是接口类型的应用,会不合适。因此需要在不改版核心代码(system 目录下文件),来改变对异常及 404 等相关异常的处理。
方法说明
ci 框架 3.0 比 2.0 有比较大的改动,其中之一就是对异常的处理。以下是 CodeIgniter-3.1.8\system\core\CodeIgniter.php 中对异常处理的部分代码
/*
* ——————————————————
* Define a custom error handler so we can log PHP errors
* ——————————————————
*/
set_error_handler(‘_error_handler’);
set_exception_handler(‘_exception_handler’);
register_shutdown_function(‘_shutdown_handler’);
…
以上括号内的方法均在 common.php 中以 function_exists 为前提声明。
…
if (! function_exists(‘_exception_handler’))
{
…
代码实现
我们简单粗暴的在项目入口文件 index.php 中重写以下方法
/**
* 推送到 redis 异常队列
* @time 2019/3/21 15:29
* @author
* @param $msg
* @return bool|int|string
*/
function redis_list_add($msg)
{
ini_set(‘default_socket_timeout’, -1);
$v = explode(‘:’, $_SERVER[‘SITE_REDIS_SERVER’]);
if (is_array($v) && !empty($v)) {
try {
$redis = new redis();
$redis->pconnect($v[0], $v[1]);
$trace = $_SERVER[‘SERVER_NAME’] . ” exception\n”;
$trace .= “clint ip is {$_SERVER[‘REMOTE_ADDR’]} ” . “,server is ” . $_SERVER[‘SERVER_NAME’] . “(” . $_SERVER[‘SERVER_ADDR’] . “)”.”\n”;
$trace.= “path is “.(isset($_SERVER[‘REQUEST_URI’])?$_SERVER[‘REQUEST_URI’]:”empty”).”\n”;
$trace .= “request params is =” . print_r($_POST, true);
return $redis->LPUSH(‘CC_PHP_ERROR_WARNING’, $trace . $msg);
} catch (Exception $e) {
return $e->getMessage();
}
}
}
/**
* 优先重写 common.php 中对应方法
* @time 2019/3/21 16:19
* @author
* @param $severity
* @param $message
* @param $filepath
* @param $line
*/
function _error_handler($severity, $message, $filepath, $line)
{
$is_error = (((E_ERROR | E_PARSE | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR | E_STRICT) & $severity) === $severity);
if ($is_error) {
$error_msg = ($message . “\n” . $filepath . “\n” . $line);
redis_list_add($error_msg);
exit(json_encode([‘success’ => ‘-1’, ‘code’ => 501, ‘msg’ => ‘error’]));
}
}
/**
* 捕获 php 本身语法,对象调用,参数类型传递等错误
* 优先重写 common.php 中对应方法
* ParseError,object(Error),TypeError,Error
* @time 2019/3/20 18:33
* @author
* @param $exception
*/
function _exception_handler($exception)
{
$_tmp =& load_class(‘Exceptions’, ‘core’);
if (!empty($exception)) {
$error_msg = ($exception->getMessage() . “\n” . $exception->getTraceAsString());
redis_list_add($error_msg);
exit(json_encode([‘success’ => ‘-1’, ‘code’ => 501, ‘msg’ => ‘exception’]));
}
}
/**
* 优先重写 common.php 中对应方法
* require_once(‘no_exists.php’)
* @time 2019/3/21 9:49
* @author
*/
function _shutdown_handler()
{
$last_error = error_get_last();
if (isset($last_error) &&
($last_error[‘type’] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING))) {
redis_list_add($msg = $last_error[‘message’] . “\n” . $last_error[‘file’] . “\n” . $last_error[‘line’] . “\n”);
exit(json_encode([‘success’ => ‘-1’, ‘code’ => 501, ‘msg’ => ‘shutdown’]));
}
}
/**
* 优先重写 common.php 中对应方法
* ci 框架内部的 load 异常、config 异常、loader 异常等会自动抛出,
* 但 common.php 中的函数定义之类错误无法捕捉
* @time 2019/3/20 18:46
* @author
* @param $message
* @param int $status_code
*/
function show_error($message)
{
redis_list_add($message);
exit(json_encode([‘success’ => ‘-1’, ‘code’ => ‘503’, ‘msg’ => ‘ci_exception_1’]));
}
/**
* 优先重写 common.php 中对应方法
* @time 2019/3/21 15:34
* @author
* @param string $page
*/
function show_404($page = ”)
{
redis_list_add(“url: ” . $page . ” not found”);
exit(json_encode([‘success’ => ‘-1’, ‘code’ => ‘404’, ‘msg’ => ‘Not Found’]));
}
延伸
在基类中可以处理
错误等级区分对待