PHPで文字列を出力する方法を、出力先ごとに整理して解説します。
結論から書くと、画面に出すなら echo、ブラウザの開発ツールのコンソールに出すなら console.log() を埋め込む方法、画面を汚さずログに残すなら error_log() を使います。
デバッグのつもりで echo した文字が本番の画面に出てしまった、という事故はよくあります。出力先を使い分けられるようにしておくと、そもそもその事故が起きません。
この記事では3つの出力方法と、配列を確認するときの関数の選び方、そしてコンソール出力で見落とされがちなエスケープの注意点までまとめます。動作は PHP 8.5 で確認しています。
スポンサーリンク
出力先で使い分ける3つの方法
結論:何を確認したいかではなく、どこに出したいかで選びます。
▼出力方法の使い分け
| 方法 | 出力先 | 使う場面 |
|---|---|---|
echo |
画面(HTML) | そのまま表示したい値 |
console.log() を埋め込む |
ブラウザの開発ツール | 画面を崩さず値を見たい |
error_log() |
サーバーのログファイル | 本番・非同期処理・APIの中 |
以下、それぞれ解説していきます。
echoを使って文字列を出力する
結論:echo は、渡した文字列をそのまま画面に出力します。PHPでいちばん基本的な出力です。
echo "出力したい文字列";
複数の値をカンマで並べて渡すこともできます。
$name = "りん";
echo "こんにちは、", $name, "さん";
変数の値を画面に出すときは、必ずエスケープしてください。ユーザーが入力した値をそのまま echo すると、HTMLタグやスクリプトがそのまま解釈されます。
// 危険:入力値がそのままHTMLとして解釈される
echo $comment;
// 安全:HTMLの特殊文字を実体参照に変換する
echo htmlspecialchars($comment, ENT_QUOTES, 'UTF-8');
PHP 8.1 以降は htmlspecialchars() の既定が ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 になったため、引数を省略してもシングルクォートまで変換されます。ただし明示しておくほうが、古い環境へ持っていったときに挙動が変わりません。
スポンサーリンク
HTMLのコード上でechoを使って出力する
結論:HTMLの中に値を差し込むときは、PHPの開始・終了タグで囲みます。短縮タグ <?= ?> を使うと echo を書かずに済みます。
<body>
<?php
echo "出力したい文字列";
?>
</body>
同じ内容を短縮タグで書くとこうなります。
<body>
<?= htmlspecialchars($text, ENT_QUOTES, 'UTF-8') ?>
</body>
<?= は <?php echo の短縮形です。PHP 5.4 以降は short_open_tag の設定に関係なく常に使えるので、テンプレートの中ではこちらのほうが読みやすくなります。
なお、ファイルの末尾に閉じタグ ?> は書かないのが定石です。閉じタグの後ろに改行や空白が残ると、それが出力に混ざってヘッダー送信のエラーになることがあります。
開発ツールのコンソールに出力する
結論:画面に出したくない値は、<script> タグを出力して console.log() に渡します。ブラウザの開発ツールのコンソールで確認できます。
配列やオブジェクトを確認したいときに向いています。画面のレイアウトを崩さずに中身を見られるので、CSSの調整中でも使えます。
<?php
$data = ["name" => "りん", "tags" => ["php", "css"]];
echo '<script>';
echo 'console.log(' . json_encode($data, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE) . ')';
echo '</script>';
?>
json_encodeにフラグを付ける理由
結論:フラグなしの json_encode() は危険です。値の中に </script> という文字列が入っていると、そこでスクリプトタグが閉じてしまい、続きがHTMLとして解釈されます。
たとえば、ユーザーが入力した文字列にこれが混ざっていると、任意のスクリプトを実行されます。JSON_HEX_TAG を付けると < と > が \u003C / \u003E に変換されるので、この経路が塞がります。
▼付けておくフラグ
| フラグ | 効果 |
|---|---|
JSON_HEX_TAG |
< > を変換する(これが必須) |
JSON_HEX_AMP |
& を変換する |
JSON_HEX_APOS |
' を変換する |
JSON_HEX_QUOT |
" を変換する |
JSON_UNESCAPED_UNICODE |
日本語をそのまま出す(読みやすさ用) |
JSON_UNESCAPED_UNICODE だけは安全性ではなく可読性のためのフラグです。付けないと日本語が \u308a\u3093 のようなエスケープ表記になり、コンソールでは読めますが目視の確認がしづらくなります。
なお、この方法はHTMLを出力するページでしか使えません。Ajax で JSON を返すAPIや、CLIから実行するスクリプトの中で使うと、レスポンスに <script> が混ざって壊れます。そういう場所では次の error_log() を使ってください。
スポンサーリンク
画面に出さずログに残す(error_log)
結論:error_log() は、値をサーバーのエラーログに書き出します。画面にもレスポンスにも一切出ないので、本番環境やAPIの中でも安全に使えます。
$data = ["name" => "りん", "tags" => ["php", "css"]];
// 文字列をそのまま
error_log("ここまで到達しました");
// 配列は print_r で文字列にしてから渡す
error_log(print_r($data, true));
// JSON にすると1行で収まって grep しやすい
error_log(json_encode($data, JSON_UNESCAPED_UNICODE));
print_r() の第2引数に true を渡すのを忘れないでください。省略すると画面に出力してしまい、ログには「1」とだけ記録されます。
出力先は php.ini の error_log で決まります。設定していない場合はウェブサーバーのエラーログに出ます。Apache なら error_log、nginx + PHP-FPM なら PHP-FPM のログを確認してください。
tail -f /var/log/php-fpm/error.log
配列の中身を確認する関数の選び方
結論:配列やオブジェクトの中身を見る関数は3つあります。型まで見たいなら var_dump()、構造を読みやすく見たいなら print_r()、コードとして貼り直したいなら var_export() です。
▼3つの関数の違い
| 関数 | 型の表示 | 文字列で受け取る | 向いている用途 |
|---|---|---|---|
var_dump() |
あり(型と文字数も出る) | できない | 型の取り違えを疑うとき |
print_r() |
なし | 第2引数に true |
構造をざっと見るとき |
var_export() |
あり(PHPの記法で出る) | 第2引数に true |
そのままコードに貼るとき |
「値は入っているはずなのに条件分岐に入らない」といった場面では、var_dump() を使ってください。print_r() では文字列の "0" と数値の 0、null と空文字の区別が付きません。
var_dump($value);
// string(1) "0" ← 文字列の 0
// int(0) ← 数値の 0
// NULL ← null
画面に出したくない場合は、先ほどの error_log(print_r($data, true)) と組み合わせます。
デバッグ出力を本番に残さないために
結論:出力先を error_log() に統一しておくと、消し忘れても画面には出ません。
echo や var_dump() による確認用の出力は、消し忘れるとそのまま本番の画面に出ます。特に var_dump() は変数の中身をすべて吐き出すので、内部のパスやIDが表に出てしまうことがあります。
確認用の出力は最初から error_log() で書く癖を付けておくと、この事故が起きません。どうしても画面に出したい場合は、開発環境でだけ動くように条件を付けてください。
if (getenv('APP_ENV') === 'local') {
echo '<pre>' . htmlspecialchars(print_r($data, true), ENT_QUOTES, 'UTF-8') . '</pre>';
}
PHPのローカル環境を整えるところからやり直したい場合は、MacでPHPのバージョンを切り替える方法もあわせてどうぞ。Homebrew での切り替え手順と、切り替えが反映されないときの対処をまとめています。
Laravel など、フレームワークの中でデバッグする場面が多い場合は、Dockerを使ってLaravel/Blade環境構築からscss導入までで作った環境がそのまま使えます。