対象: Symfony 7.4(symfony/runtimesymfony/error-handler、FrameworkBundle のソースで確認)
版によって挙動が変わる可能性があります。vendor/ の実コードで確認してください。

全体像

PHP のエラー(Warning・Notice など)の扱いは、2 段階で決まります。

段階 タイミング 担当 内容
1 アプリ起動直後 Symfony\Component\Runtime\Internal\SymfonyErrorHandler::register() error_reportingdisplay_errors・assertions・DebugClassLoader の設定、ErrorHandler の登録
2 カーネル boot 時 FrameworkBundle(debug.error_handler_configurator framework.php_errorslog / throw を反映して、例外化・ログ出力の対象を確定

段階 2 の throw の既定値が %kernel.debug% であることが、APP_DEBUG による最大の差異です(後述)。

段階 1: SymfonyErrorHandler

// vendor/symfony/runtime/Internal/SymfonyErrorHandler.php(抜粋)
public static function register(bool $debug): void
{
    // ...
    error_reporting(\E_ALL & ~\E_DEPRECATED & ~\E_USER_DEPRECATED);

    if (!\in_array(\PHP_SAPI, ['cli', 'phpdbg', 'embed'], true)) {
        ini_set('display_errors', $debug);
    } elseif (!filter_var(\ini_get('log_errors'), \FILTER_VALIDATE_BOOL) || \ini_get('error_log')) {
        // CLI - display errors only if they're not already logged to STDERR
        ini_set('display_errors', 1);
    }

    if (0 <= \ini_get('zend.assertions')) {
        ini_set('zend.assertions', (int) $debug);
    }
    ini_set('assert.active', 1);
    ini_set('assert.exception', 1);

    if ($debug) {
        DebugClassLoader::enable();
    }

    ErrorHandler::register(new ErrorHandler(new BufferingLogger(), $debug));
}

error_reporting

error_reporting(\E_ALL & ~\E_DEPRECATED & ~\E_USER_DEPRECATED)APP_DEBUG に関係なく設定されます。

意味
\E_ALL 全エラーレベルを対象にする
~\E_DEPRECATED E_DEPRECATED(PHP 本体の非推奨警告)を除外
~\E_USER_DEPRECATED E_USER_DEPRECATEDtrigger_error による非推奨警告)を除外

つまり「Deprecated 系以外を PHP のエラー報告対象にする」設定です。

[!NOTE] error_reporting() は、PHP 自身が表示・ログするエラーの範囲を決める設定です。カスタムエラーハンドラの呼び出しは抑止しません(PHP マニュアルに明記)。
Symfony の ErrorHandlerset_error_handler() の第 2 引数(mask)に「例外化する種別 | ログする種別」を渡して登録します。Deprecated 系もこのハンドラに届くため、PHP 側の表示から外しても、Symfony 側でログ出力(info)できます。

display_errors

SAPI 挙動
Web(cli / phpdbg / embed 以外) ini_set('display_errors', $debug)APP_DEBUG=true なら 1、false なら 0)
CLI log_errors が無効、または error_log が設定されている場合のみ display_errors=1log_errors 有効かつ error_log 未設定なら変更しない(PHP の設定のまま)

CLI の分岐は $debug を参照しないため、APP_DEBUG による差異はありません。ただし「常に 1」ではない点に注意してください。

DebugClassLoader

APP_DEBUG=true のときだけ有効になります。クラスのロード時に、開発者向けの次のような問題を検出して非推奨警告を出します。

  • クラス名の大文字・小文字の不一致(ファイル名との差異)
  • @deprecated なクラス・メソッドの利用、@final の違反
  • 戻り値型の宣言漏れなど、将来の BC break につながる書き方

本番では不要なため無効です。エラーの例外化には影響しません。

段階 2: FrameworkBundle による例外化の設定

framework.php_errors の既定値は次のとおりです。

設定 既定値 意味
throw %kernel.debug% PHP エラーを \ErrorException として投げる
log true PHP エラーをアプリのロガー(Monolog)へ出力する

throwfalse の場合、FrameworkBundle は throwAt(0) 相当の設定を行います。このとき例外化されるのは、常に例外化される E_RECOVERABLE_ERRORE_USER_ERROR だけです。

APP_DEBUG による差異(カーネル boot 後)

項目 APP_DEBUG=true APP_DEBUG=false
Warning / Notice の例外化 される されない(ログ出力のみ)
E_RECOVERABLE_ERROR / E_USER_ERROR 例外化 例外化(同じ)
Deprecated 系 例外化されない(ログのみ) 例外化されない(ログのみ)
display_errors(Web) 1 0
display_errors(CLI) 前述の条件による(同じ) 前述の条件による(同じ)
DebugClassLoader 有効 無効
zend.assertions(既定が 0 以上のとき) 1 0

[!WARNING] ErrorHandlerprivate int $thrownErrors = 0x1FFF;プロパティの初期値です。カーネル boot 前(.env の読み込みやカーネル生成の最中)はこの値が有効で、Warning も例外化されます。boot 後は php_errors.throw が反映されます。

本番でもローカルと同じ挙動にしたい場合

Warning・Notice を本番でも例外化するには、明示的に設定します。

# config/packages/framework.yaml
framework:
    php_errors:
        throw: true

逆に、ローカルでも本番と同じ「ログのみ」にしたい場合は throw: falsewhen@dev などに設定します。

例外化される対象

  • Warning・Notice などの非致命エラーは \ErrorException になります(ErrorHandler::handleError())。
  • PHP 7 以降の \ErrorTypeErrorDivisionByZeroError など)は最初から例外であり、\Error のまま投げられます。ErrorException にはなりません。
  • 回復不能な Fatal(E_ERROR など)は shutdown 時に検出され、FatalError として扱われます。
  • @ 演算子で抑制されたエラーは、(E_RECOVERABLE_ERROR などを除き)例外化されません。

確認方法

# 設定の確認(throw / log の実際の値)
bin/console debug:config framework php_errors

# 実挙動の確認: Warning を出すコマンドを作成して、環境ごとに実行する
#   trigger_error('sample', E_USER_WARNING);
APP_ENV=dev  APP_DEBUG=1 bin/console app:sample   # 例外になる
APP_ENV=prod APP_DEBUG=0 bin/console app:sample   # ログのみ(error レベル)

まとめ

  • error_reporting と Deprecated 系の除外は、APP_DEBUG に関係なく共通です。
  • Warning・Notice の例外化は APP_DEBUG によって変わりますframework.php_errors.throw の既定が %kernel.debug%)。APP_DEBUG=false ではログのみです。
  • CLI の display_errorsAPP_DEBUG に依存せず、log_errors / error_log の設定で決まります。
  • 環境間の挙動を揃えるには、framework.php_errors.throw を明示するのが確実です。
  • ログレベルの対応は Monolog のエラーハンドリング を参照してください。