CodeIgniter3(以下CI3)でエラー・例外が発生した場合の処理の流れについてです。
対象のバージョンはCodeIgniter3.0.6、PHPは5.6.22で確認しました。
CodeIgniterにおけるエラー・例外発生時の仕組み。
まず前提としてPHPではset_error_handler等を使うことによりエラーハンドラ・例外ハンドラを定義することができます。
マニュアル。
http://php.net/manual/ja/function.set-error-handler.php
そしてCI3においてはCodeIgniter.phpでこれらのハンドラを設定しています。
set_error_handler('_error_handler');
set_exception_handler('_exception_handler');
register_shutdown_function('_shutdown_handler');
そしてCommon.phpにこれらの関数に定義があります。
基本的にはExceptionクラスをロードして、対応したメソッドを呼び出します。具体的な処理はExceptionクラスにまとめられています。
if ( ! function_exists('_error_handler'))
{
function _error_handler($severity, $message, $filepath, $line)
{
$is_error = (((E_ERROR | E_COMPILE_ERROR | E_CORE_ERROR | E_USER_ERROR) & $severity) === $severity);
if ($is_error)
{
set_status_header(500);
}
if (($severity & error_reporting()) !== $severity)
{
return;
}
$_error =& load_class('Exceptions', 'core');
$_error->log_exception($severity, $message, $filepath, $line);
if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors')))
{
$_error->show_php_error($severity, $message, $filepath, $line);
}
if ($is_error)
{
exit(1); // EXIT_ERROR
}
}
}
if ( ! function_exists('_exception_handler'))
{
function _exception_handler($exception)
{
$_error =& load_class('Exceptions', 'core');
$_error->log_exception('error', 'Exception: '.$exception->getMessage(), $exception->getFile(), $exception->getLine());
if (str_ireplace(array('off', 'none', 'no', 'false', 'null'), '', ini_get('display_errors')))
{
$_error->show_exception($exception);
}
exit(1); // EXIT_ERROR
}
}
if ( ! function_exists('_shutdown_handler'))
{
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)))
{
_error_handler($last_error['type'], $last_error['message'], $last_error['file'], $last_error['line']);
}
}
}
そしてException.phpに実際の処理が書かれています。
ここでビューが読み込まれ、画面にエラーメッセージ表示される形です。
public function show_exception($exception)
{
$templates_path = config_item('error_views_path');
if (empty($templates_path))
{
$templates_path = VIEWPATH.'errors'.DIRECTORY_SEPARATOR;
}
$message = $exception->getMessage();
if (empty($message))
{
$message = '(null)';
}
if (is_cli())
{
$templates_path .= 'cli'.DIRECTORY_SEPARATOR;
}
else
{
set_status_header(500);
$templates_path .= 'html'.DIRECTORY_SEPARATOR;
}
if (ob_get_level() > $this->ob_level + 1)
{
ob_end_flush();
}
ob_start();
include($templates_path.'error_exception.php');
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
}
public function show_php_error($severity, $message, $filepath, $line)
{
$templates_path = config_item('error_views_path');
if (empty($templates_path))
{
$templates_path = VIEWPATH.'errors'.DIRECTORY_SEPARATOR;
}
$severity = isset($this->levels[$severity]) ? $this->levels[$severity] : $severity;
// For safety reasons we don't show the full file path in non-CLI requests
if ( ! is_cli())
{
$filepath = str_replace('\\', '/', $filepath);
if (FALSE !== strpos($filepath, '/'))
{
$x = explode('/', $filepath);
$filepath = $x[count($x)-2].'/'.end($x);
}
$template = 'html'.DIRECTORY_SEPARATOR.'error_php';
}
else
{
$template = 'cli'.DIRECTORY_SEPARATOR.'error_php';
}
if (ob_get_level() > $this->ob_level + 1)
{
ob_end_flush();
}
ob_start();
include($templates_path.$template.'.php');
$buffer = ob_get_contents();
ob_end_clean();
echo $buffer;
}
画面イメージ
Exceptionで呼び出されたメソッドに応じて、実際に表示される画面イメージはこのようになります。
実行したコードはこちら。
<?php
class Sample extends CI_Controller {
public function normal()
{
$this->load->view('view');
}
public function exception()
{
throw new Exception("例外発生!");
$this->load->view('view');
}
public function php_error()
{
throw new Exceptio(); //typo
$this->load->view('view');
}
public function error()
{
show_error("エラー表示関数を呼んだ");
$this->load->view('view');
}
}
?>
<html>
<head>
<title>タイトル</title>
</head>
<body>
<h1>正常に表示されました</h1>
</body>
</html>
上記をそれぞれ実行した画面のキャプチャがこちら。
エラーに関しては、PHPのデフォルト時の画面表示とそう大きく変わらないですね。
normal
exception
php_error
error(参考)
カスタムするには
デフォルトのException.phpを継承して、対象のメソッドをオーバーライドすることで任意のエラーページに遷移させたり、独自のログ出力など共通処理を追加することが可能です。
これのExceptionsを継承する形です。
http://www.codeigniter.com/user_guide/general/core_classes.html
以上。