タイトル: var_dumpをログ出力
SEOタイトル: PHP var_dump をログ出力する完全ガイド
| この記事の要点 |
|
なぜ var_dump はログに残らない
var_dump() / print_r() / echo はすべて標準出力 (STDOUT) に書き出します。CLI で実行中なら画面に出ますが、Web リクエスト中なら HTML レスポンスに混入し、PHP-FPM のerror_log には記録されません。
| 関数 | 出力先 | 文字列で受け取れる |
|---|---|---|
var_dump($x) | 標準出力 | 不可(後述の ob で代用) |
print_r($x) | 標準出力 | print_r($x, true) で文字列化 |
var_export($x) | 標準出力 | var_export($x, true) で文字列化 |
error_log($s) | error_log 指定先 | 引数自体が文字列 |
方法1: ob_start で var_dump をキャプチャ
function logDump($var, string $label = ''): void {
ob_start();
var_dump($var);
$output = ob_get_clean(); // バッファ取得 + クリア
error_log("[DUMP] $label\n" . $output);
}
logDump($_POST, '$_POST');
logDump($user, 'after load');
方法2: print_r($x, true) で文字列化
シンプルな配列やオブジェクトなら print_r($x, true) で十分です:
$user = ['id' => 1, 'name' => '田中', 'roles' => ['admin', 'editor']];
// 文字列として取得
$str = print_r($user, true);
error_log($str);
// var_export はより PHP らしい表現(再代入可能な形式)
error_log(var_export($user, true));
// array (
// 'id' => 1,
// 'name' => '田中',
// ...
// )
方法3: Laravel の Log ファサード
use Illuminate\Support\Facades\Log;
// 配列やオブジェクトは第二引数の context に渡すと自動で JSON 化
Log::debug('User loaded', ['user' => $user]);
Log::info('処理完了', ['count' => $count, 'duration_ms' => $ms]);
// レベル別
Log::emergency($msg); // 緊急
Log::alert($msg); // 警告
Log::critical($msg);
Log::error($msg);
Log::warning($msg);
Log::notice($msg);
Log::info($msg);
Log::debug($msg); // ★ デバッグ
// 専用チャンネルに分離
Log::channel('debug')->info('dev only', $context);
Log::channel('slack')->critical('本番ダウン', $context);
// var_dump 的に詳細出力したい
Log::debug('user dump: ' . print_r($user, true));
Log::debug('user json: ' . json_encode($user, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
設定は config/logging.php と .env:
# .env
LOG_CHANNEL=stack
LOG_LEVEL=debug # 本番は info / warning に
方法4: Symfony VarDumper
Laravel 同梱の dump() / dd() は Symfony VarDumper を使っています。本来は画面出力ですが、ログ用ハンドラに差し替え可能です:
use Symfony\Component\VarDumper\Cloner\VarCloner;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\VarDumper;
VarDumper::setHandler(function ($var) {
$cloner = new VarCloner();
$dumper = new CliDumper();
$output = fopen('php://memory', 'r+');
$dumper->dump($cloner->cloneVar($var), $output);
rewind($output);
\Log::debug(stream_get_contents($output));
fclose($output);
});
// 以降の dump() がすべてログへ
dump($user);
| 関数 | 動作 |
|---|---|
dump($x) | カラフルに表示、処理は続く |
dd($x) | 表示後に die() |
ddd($x) | 表示後に die(Ignition + Spatie ray) |
方法5: error_log のフォーマット整形
function dumpToLog($var, string $label = '', int $depth = 0): void {
$now = date('Y-m-d H:i:s');
$pid = getmypid();
$caller = debug_backtrace()[1] ?? [];
$file = basename($caller['file'] ?? '?');
$line = $caller['line'] ?? '?';
ob_start();
var_dump($var);
$body = ob_get_clean();
error_log("[$now][PID:$pid][$file:$line] $label\n$body");
}
dumpToLog($request->all(), 'request');
// [2026-06-10 10:23:45][PID:1234][UserController.php:42] request
// array(2) {
// ["email"]=>
// string(...) "..."
// ...
// }
機密情報のマスキング
本番ログに password / credit_card / token が乗ると重大インシデント。マスク処理を必ず挟む:
function maskSensitive(array $data): array {
$sensitive = ['password', 'password_confirmation', 'token',
'api_key', 'secret', 'credit_card', 'cvv'];
foreach ($data as $k => $v) {
if (in_array(strtolower($k), $sensitive, true)) {
$data[$k] = '***MASKED***';
} elseif (is_array($v)) {
$data[$k] = maskSensitive($v);
}
}
return $data;
}
Log::debug('request', maskSensitive($request->all()));
Laravel なら設定でも可能:
// app/Exceptions/Handler.php
protected $dontFlash = [
'current_password', 'password', 'password_confirmation',
];
本番でのデバッグ手段
| ツール | 用途 |
|---|---|
| Laravel Telescope | SQL / リクエスト / ジョブ / メールを Web UI で |
| Laravel Debugbar | 画面下部にデバッグ情報(開発用) |
| Xdebug | ブレークポイント付きステップ実行 |
| Sentry / Bugsnag | 例外・エラーを集約 |
| Datadog / NewRelic APM | パフォーマンス可視化 |
| Spatie Ray | 専用デスクトップアプリにダンプ送信 |
FAQ
Q: error_log() はどこに書かれる?
A: php.ini の error_log 設定先。未設定なら SAPI のデフォルト(Apache: error_log、PHP-FPM: fpm.conf の error_log)。CLI は標準エラーへ。
Q: 巨大配列を dump するとログが膨らむ
A: VarDumper の $cloner->setMaxItems(50) や、配列なら array_slice($x, 0, 10) で先頭だけ。本番では Telescope の方が UI 上で展開できて便利。
Q: Log::debug() がログに出ない
A: .env の LOG_LEVEL を確認。info 以上だと debug は捨てられます。