uzullaがブログ

uzullaがブログです。

PHPの扱いづらいエラーをうまい感じにやるのとPHPerKaigi2019で登壇しますの話

今月末開催のPHPerKaigiがみえてきましたね!!

phperkaigi.jp

私もトークする予定です。

fortee.jp

さて、

結構昔にPHPのエラーの話をかきまして、

uzulla.hateblo.jp

uzulla.hateblo.jp

これらもだいぶ古くなったなあ、ということで最近PHP7.3と一緒につかっているタレをかいておきますね。

こちらが最近のタレの様子です

<?php
declare(strict_types=1);

// defines
define("START_MICRO_SEC", microtime(true)); // measure consume time.

// error handling settings
ini_set("display_errors", "0");
ini_set("display_startup_errors", "0");
ini_set('html_errors', "0");
error_reporting(E_ALL);
// Noticeを含むすべてのエラーをキャッチしてExceptionに変換
set_error_handler(function ($severity, $message, $file, $line) {
    throw new ErrorException($message, 0, $severity, $file, $line);
});
// FatalErrorなどリカバリできないエラーをキャッチ
register_shutdown_function(function () {
    $error = error_get_last();
    if (!is_array($error) || !($error['type'] & (E_ERROR | E_PARSE | E_CORE_ERROR | E_USER_ERROR | E_COMPILE_ERROR | E_RECOVERABLE_ERROR))) {
        // 処理時間ログ
        if (getenv('LOGGING_CONSUME_TIME') !== false) {
            $consume_ms = (microtime(true) - START_MICRO_SEC) * 1000;
            error_log("consume time: " . sprintf("%.2f ms", $consume_ms));
            $memory = memory_get_peak_usage(false);
            error_log("consume memory: " . sprintf("%.2f kbyte", $memory / 1024));
        }
        return; // 正常終了系
    }

    // 異常終了系

    // Logging un-excepted output buffer(debug|error messages)
    $something = ob_get_contents();
    if (strlen($something) > 0) {
        error_log($something);
    }
    ob_end_clean();

    // Error Logging
    error_log("Uncaught Fatal Error: {$error['type']}:{$error['message']} in {$error['file']}:{$error['line']}");

    // response error
    if (!headers_sent()) {
        http_response_code(500);
    }
    echo "500 internal server error";
});

try {
    // enable output buffer
    ob_start();

    // ここから
    require(__DIR__ . "/vendor/autoload.php");
    echo "hello!";
    // ここまでにアプリを書く

    ob_end_flush();

} catch (\Throwable $e) {
    // Uncaught Exception

    // Logging un-excepted output buffer(debug|error messages)
    $something = ob_get_contents();
    if (strlen($something) > 0) {
        error_log($something);
    }
    ob_end_clean();

    // Stack trace Logging
    $error_class_name = get_class($e);
    error_log("Uncaught Exception {$error_class_name}: {$e->getMessage()} in {$e->getFile()}:{$e->getLine()}\n{$e->getTraceAsString()}");

    // response error
    if (!headers_sent()) {
        http_response_code(500);
    }
    echo "500 internal server error";
}

こう、非常に富豪なHelloworldですが、まあこれくらいやっておくとだいぶ便利(主観です)かなと思います。

Noticeも通らないですし、へんなログ出力もなくなります。

ただ、Output bufferをつかっているので、フレームワークによっては少々食い合わせに注意が必要です。

これにもうちょっと継ぎ足すならログ周りかなとおもいますが、クリティカルなエラーのあとだとライブラリのロガーは挙動が怪しい事があるので、標準装備のerror_log()を使うほうが良いかなと思います。あ、あとPsyshでシェルに落ちるとかも便利ですよね。

まあ、なにやってんのかわかんねえ!という方もいらっしゃるかと思いますが、大丈夫、こういうのは普通の人は自分でかきません、有名なフレームワークにまかせましょう!!

…といったような話をPHPerKaigiでできるといいなとおもいますので、ぜひ皆さんご参加ください!!

練馬で僕と握手!!!

こちらからは以上です。