php エラーを例外に飛ばしたい(try-catch、set_error_handler)

作成日:2019-05-23, 更新日:2021-11-24

基本

▼最初に読み込ませるようなファイルとかに記載

set_error_handler(function($error_no, $error_msg, $error_file, $error_line, $error_vars) {
  if (error_reporting() === 0) {
    return;
  }
  throw new ErrorException($error_msg, 0, $error_no, $error_file, $error_line);
});

他、関係のあるヤツら。
・set_exception_handler - 「try catch」で例外がキャッチされなかったときのデフォルトの例外ハンドラを設定
・register_shutdown_function - シャットダウン時に実行する関数を登録するヤツ

カスタマイズ

・個人的に・・・「try catch」で処理をしたい。
→PHPエラーのときは「強制終了」、それ以外は「強制終了しない」としたい

▼こんな感じにしたい

try {
  〇〇〇
}
catch (Exception $e) {
  if ( PHPエラーのとき ) {
    〇〇〇
    exit;
  }
  else {
    〇〇〇
  }
}

ソース

▼set_error_handler()を少し修正

set_error_handler(function($error_no, $error_msg, $error_file, $error_line, $error_vars) {
  if (error_reporting() === 0) {
    return;
  }
  throw new ErrorException($error_msg, $error_no, $error_no, $error_file, $error_line);
});

▼「try catch」のトコ

try {
  〇〇〇
}
catch (Exception $e) {
  // E_ERROR、E_PARSE、E_USER_ERRORは例外を補足出来ないらしい
  switch($e->getCode()) { 
    case 0:                   $errPHP = '';                    break; // throw new Exception()されたヤツ。
    case E_ERROR:             $errPHP = 'E_ERROR';             break; // 1      'Fatal Error',                ←例外に入る前に落ちると思われる
    case E_WARNING:           $errPHP = 'E_WARNING';           break; // 2      'Warning',
    case E_PARSE:             $errPHP = 'E_PARSE';             break; // 4      'Parsing Error',              ←例外に入る前に落ちると思われる
    case E_NOTICE:            $errPHP = 'E_NOTICE';            break; // 8      'Notice',
    case E_CORE_ERROR:        $errPHP = 'E_CORE_ERROR';        break; // 16     'Core Error',
    case E_CORE_WARNING:      $errPHP = 'E_CORE_WARNING';      break; // 32     'Core Warning',
    case E_COMPILE_ERROR:     $errPHP = 'E_COMPILE_ERROR';     break; // 64     'Compile Error',
    case E_COMPILE_WARNING:   $errPHP = 'E_COMPILE_WARNING';   break; // 128    'Compile Warning',
    case E_USER_ERROR:        $errPHP = 'E_USER_ERROR';        break; // 256    'User Error',                 ←例外に入る前に落ちると思われる
    case E_USER_WARNING:      $errPHP = 'E_USER_WARNING';      break; // 512    'User Warning',
    case E_USER_NOTICE:       $errPHP = 'E_USER_NOTICE';       break; // 1024   'User Notice',
    case E_STRICT:            $errPHP = 'E_STRICT';            break; // 2048   'Runtime Notice',
    case E_RECOVERABLE_ERROR: $errPHP = 'E_RECOVERABLE_ERROR'; break; // 4096   'Runtime Recoverable error',  ←例外にくるか来ないか微妙(未調査)
    case E_DEPRECATED:        $errPHP = 'E_DEPRECATED';        break; // 8192   'Runtime Deprecated code usage',
    case E_USER_DEPRECATED:   $errPHP = 'E_USER_DEPRECATED';   break; // 16384  'User Deprecated code usage',
  } 
  if ( $errPHP!='' ) {
    〇〇〇
    exit;
  }
  else {
    〇〇〇
  }
}

catchされない場合のログ保存

サーバ側で処理ができるとか、できないとか・・・よくわからんから設定する。

register_shutdown_function(function() {
  $error = error_get_last();
  if ($error===null || !($error['type'] & (E_ERROR | E_PARSE | E_USER_ERROR | E_RECOVERABLE_ERROR))) {
    // エラーが無い、catchされたモノたちは何もしない
    return;
  }
  
  // ▼ログ保存させるかメール送信させるか:ひとまずログ保存
  
  $err = 'unknown';
  switch($error['type']) { 
    case E_ERROR:             $err = 'Fatal Error';               break;
    case E_PARSE:             $err = 'Parsing Error';             break;
    case E_USER_ERROR:        $err = 'User Error';                break;
    case E_RECOVERABLE_ERROR: $err = 'Runtime Recoverable error'; break;
  } 
  
  // ログ保存
  $path = __DIR__ . DIRECTORY_SEPARATOR . '〇〇〇' . DIRECTORY_SEPARATOR . '〇〇〇.log';
  $log = date('Y-m-d H:i:s') . ' '
       . $err . ': '
       . $error['message'] . ' / '
       . $error['file'] . '(' . $error['line'] . ')'
       . "\n";
  file_put_contents($path, $log, FILE_APPEND | LOCK_EX);
});

▼下記のような感じで「set_error_handler()」と同じとこに記載。

set_error_handler(〇〇〇);
register_shutdown_function(〇〇〇);

関連項目

php 一時的にwarnigを拾いたい(set_error_handler()、restore_error_handler())