var_dump は「型と長さまで見える表示」、print_r は「人が読みやすい表示」、var_export は「PHPコードとしてそのまま貼り直せる表示」です。 3つとも変数の中身を確認する関数ですが、null・false・空文字の見え方、戻り値として文字列を受け取れるか、循環参照を扱えるかがそれぞれ異なります。

この記事では、同じ値を3つの関数に通した出力を PHP 8.4.21(CLI)で実際に実行して並べ、違いを比較表にまとめました。あわせて、ブラウザで崩さずに見る pre タグ整形、error_log やファイルへの書き出し、ob_start で var_dump を文字列にする方法、Xdebug・debug_zval_dump・json_encode・dump() / dd() との使い分けまで、コピペで使える形で紹介します。

var_dump・print_r・var_exportの早見表

比べる点 var_dump print_r var_export
ひとことで言うと 型と長さまで見える 人が読みやすい PHPコードとして貼り直せる
型の表示 あり(int(0)、string(1) "0") なし 引用符と小数点で区別できる(0 と '0' と 0.0)
null の表示 NULL 何も表示されない NULL
false の表示 bool(false) 何も表示されない false
空文字の表示 string(0) "" 何も表示されない ''
文字列として受け取る 引数では不可(ob_start を使う) 第2引数に true 第2引数に true
複数の変数を一度に渡す できる できない(1つだけ) できない(1つだけ)
出力をPHPコードとして再利用 できない できない できる(配列・スカラー・stdClass・Enum)
循環参照 *RECURSION* と表示して続行 *RECURSION* と表示して続行 Warning を出し、その箇所を NULL にする
private / protected の表示 表示する(可視性つき) 表示する(可視性つき) 表示する(可視性の情報は出ない)
向いている場面 型の違いを調べる 配列の形をざっと見る、ログに残す 設定やテストデータとして保存する

迷ったときは、型が関わる調査なら var_dump、配列の形を見るだけなら print_r、あとでコードに貼るなら var_export を選ぶと用が足ります。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PHP var_dump・print_r・var_exportの違いと配列表示」

同じ値を3つの関数に通すとこう表示される

まずは、紛らわしい値を同じ順番で3つの関数に通します。次のコードは保存してそのまま実行できます。

<?php
// compare.php(PHP 8.4.21 で実行)
$vals = [
    'null'  => null,
    'false' => false,
    'true'  => true,
    '0'     => 0,
    '1.0'   => 1.0,
    "''"    => '',
    "'0'"   => '0',
    "'abc'" => 'abc',
    '[]'    => [],
];
foreach ($vals as $label => $v) {
    echo "--- $label\n";
    echo "print_r   : [", print_r($v, true), "]\n";
    echo "var_dump  : "; var_dump($v);
    echo "var_export: ", var_export($v, true), "\n";
}

実行結果を表に整理すると次のとおりです(print_r は前後を [ ] で囲んで、空であることが見えるようにしています)。

渡した値 print_r var_dump var_export
null [](空) NULL NULL
false [](空) bool(false) false
true [1] bool(true) true
0 [0] int(0) 0
1.0 [1] float(1) 1.0
'' [](空) string(0) "" ''
'0' [0] string(1) "0" '0'
'abc' [abc] string(3) "abc" 'abc'
[] Array ( ) array(0) { } array ( )

ここから読み取れるポイントは3つです。

  • print_r では null・false・空文字がすべて「何も表示されない」 ため、この3つを見分けられません。true と整数の 1 と小数の 1.0 も、どれも 1 と表示されます。
  • var_dump は型名と長さがつく ので、0 と '0'、null と false を確実に区別できます。string(3) の数字はバイト数です(UTF-8 の「ノート」は string(9) になります)。
  • var_export は PHP のリテラルの形 で出るので、引用符の有無で文字列か数値かがわかり、1.0 のように小数点も残ります。

print_r で空に見える理由は、print_r がスカラー値を文字列に変換して出力するためです。PHP では false と null を文字列にすると空文字になります。

<?php
echo "[" . false . "][" . null . "][" . true . "]\n";
[][][1]

小数は関数によって桁数が変わる

小数の表示にも違いがあります。

<?php
$x = 0.1 + 0.2;
print_r($x); echo "\n";
var_dump($x);
var_export($x); echo "\n";
0.3
float(0.30000000000000004)
0.30000000000000004

print_r は丸めた値、var_dump と var_export は内部の値をそのまま再現できる桁数 で表示します。計算結果が期待と合わないときは、var_dump で確かめると原因を見つけやすくなります。

ネストした配列の中身を表示する

次は、入れ子になった配列です。

<?php
$a = ['id' => 1, 'tags' => ['a', 'b'], 'opt' => null, 'ok' => false];
print_r($a);
var_dump($a);
var_export($a);

print_r の出力です。

Array
(
    [id] => 1
    [tags] => Array
        (
            [0] => a
            [1] => b
        )

    [opt] => 
    [ok] => 
)

var_dump の出力です。

array(4) {
  ["id"]=>
  int(1)
  ["tags"]=>
  array(2) {
    [0]=>
    string(1) "a"
    [1]=>
    string(1) "b"
  }
  ["opt"]=>
  NULL
  ["ok"]=>
  bool(false)
}

var_export の出力です。

array (
  'id' => 1,
  'tags' => 
  array (
    0 => 'a',
    1 => 'b',
  ),
  'opt' => NULL,
  'ok' => false,
)
見るポイント print_r var_dump var_export
行数(この例) 11行 15行 10行
キーの書き方 [id] ["id"](文字列キーは引用符つき) 'id'
要素数 表示しない array(4) と表示 表示しない
opt(null)と ok(false) どちらも空で区別できない NULL と bool(false) NULL と false

配列の形(どのキーの下に何があるか)を見るだけなら print_r が最も短く読みやすく、値の型まで確認したいなら var_dump が向いています。var_dump は文字列キー(["id"])と整数キー([0])の違いも見分けられます。

オブジェクトの中身を表示する

public・protected・private のプロパティを持つクラスで比べます。

<?php
class Item {
    public $name = 'pen';
    protected $price = 120;
    private $stock = null;
}
$o = new Item;
print_r($o);
var_dump($o);
var_export($o);
Item Object
(
    [name] => pen
    [price:protected] => 120
    [stock:Item:private] => 
)
object(Item)#1 (3) {
  ["name"]=>
  string(3) "pen"
  ["price":protected]=>
  int(120)
  ["stock":"Item":private]=>
  NULL
}
\Item::__set_state(array(
   'name' => 'pen',
   'price' => 120,
   'stock' => NULL,
))
  • print_r と var_dump は protected・private のプロパティも可視性つきで表示 します。クラスの外から直接読めないプロパティも確認できます。
  • var_dump の #1 はオブジェクトの番号です。同じ番号なら同じインスタンス を指しているとわかります。(3) はプロパティの数です。
  • var_export は \Item::__set_state(...) という形で出力します。クラス名の先頭に \ がつく完全修飾名になるのは PHP 8.2 からです(PHP公式マニュアルの var_export の変更履歴で確認)。

Enum・クロージャ・リソースの表示

よく出会うほかの値も確認しておきます。

<?php
enum Status: string { case Open = 'open'; }
print_r(Status::Open); echo "\n";
var_dump(Status::Open);
var_export(Status::Open); echo "\n";

$fp = fopen('php://memory', 'r');
print_r($fp); echo "\n";
var_dump($fp);
var_export($fp); echo "\n";
Status Enum:string
(
    [name] => Open
    [value] => open
)

enum(Status::Open)
\Status::Open
Resource id #5
resource(5) of type (stream)
NULL
値 print_r var_dump var_export
Enum name と value を表示 enum(Status::Open) \Status::Open(コードとして使える)
リソース Resource id #5 resource(5) of type (stream) NULL
クロージャ 定義ファイル・行・引数を表示 同左(型つき) \Closure::__set_state(array())(復元はできない)

クロージャを print_r や var_dump に渡すと、定義されたファイルと行番号、引数の一覧が表示されます(PHP 8.4 で確認)。

__debugInfo で表示する内容を決める

パスワードのように画面やログへ出したくない値は、クラスに __debugInfo() を用意すると表示内容を決められます。

<?php
class Secret {
    private $password = 'p@ss';
    public $user = 'taro';
    public function __debugInfo() {
        return ['user' => $this->user, 'password' => '***'];
    }
}
$o = new Secret;
var_dump($o);
print_r($o);
var_export($o);
object(Secret)#1 (2) {
  ["user"]=>
  string(4) "taro"
  ["password"]=>
  string(3) "***"
}
Secret Object
(
    [user] => taro
    [password] => ***
)
\Secret::__set_state(array(
   'password' => 'p@ss',
   'user' => 'taro',
))

__debugInfo() が効くのは var_dump と print_r で、var_export には効きません。 var_export は元の値をそのまま出力するので、伏せたい値を持つオブジェクトをログに書くときは var_dump か print_r を選ぶと安心です。

戻り値として文字列で受け取る方法

画面に出すのではなく、文字列として受け取ってログやメールに使いたい場面は多くあります。3つの関数で方法が異なります。

<?php
$r = print_r('x', true);     var_dump($r);
$r = var_export('x', true);  var_dump($r);
$r = var_dump('x');          var_dump($r);
$r = print_r('x'); echo "\n"; var_dump($r);
string(1) "x"
string(3) "'x'"
string(1) "x"
NULL
x
bool(true)
関数 第2引数なしの戻り値 文字列で受け取る方法
print_r true(出力は画面へ) print_r($v, true)
var_export null(出力は画面へ) var_export($v, true)
var_dump null(出力は画面へ) ob_start() と ob_get_clean() で囲む

var_dump には文字列で返すための引数がありません。3行目の var_dump('x') は画面に string(1) "x" を出しただけで、戻り値は NULL です。

ob_start で var_dump を文字列にする

var_dump の出力を文字列にしたいときは、出力バッファを使います。次の関数をコピーしておくと便利です。

<?php
/** var_dump の結果を文字列で返す */
function dump_str(mixed ...$vars): string
{
    ob_start();
    var_dump(...$vars);
    return ob_get_clean();
}

echo dump_str(1.5, 'a');
float(1.5)
string(1) "a"

ob_start() から ob_get_clean() までの間の出力は画面に出ず、文字列として受け取れます。var_dump は複数の引数をまとめて渡せる ので、可変長引数(...$vars)で受けるとそのまま活かせます。

ブラウザで見やすく表示する(preタグ)

ブラウザでは改行と連続する空白がまとめられるため、print_r の出力がそのままだと1行につながって見えます。pre タグで囲むと、改行とインデントがそのまま表示されます。

<?php
$data = ['t' => '<b>x</b>'];
echo '<pre>' . htmlspecialchars(print_r($data, true), ENT_QUOTES, 'UTF-8') . '</pre>';

出力される HTML は次のとおりです。

<pre>Array
(
    [t] =&gt; &lt;b&gt;x&lt;/b&gt;
)
</pre>

値に HTML タグが含まれていても崩れないよう、htmlspecialchars を通す のがポイントです。通さずに出力すると、値の中の <b> がタグとして解釈され、中身が正しく見えなくなります。

どこで呼んだかも表示するデバッグ関数

呼び出した場所(ファイル名と行番号)も一緒に出すと、消し忘れを探しやすくなります。CLI とブラウザの両方で使える形にしたものです。

<?php
function d(mixed ...$vars): void
{
    $bt = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0];
    $where = basename($bt['file']) . ':' . $bt['line'];
    foreach ($vars as $v) {
        ob_start();
        var_dump($v);
        $out = ob_get_clean();
        if (PHP_SAPI === 'cli') {
            echo $where, "\n", $out;
        } else {
            echo '<pre>', htmlspecialchars($where . "\n" . $out, ENT_QUOTES, 'UTF-8'), '</pre>';
        }
    }
}

d(['id' => 1, 'ok' => false]);

CLI での実行結果です(ファイル名は e.php)。ブラウザ側の分岐は今回は未実行です。

e.php:13
array(2) {
  ["id"]=>
  int(1)
  ["ok"]=>
  bool(false)
}

error_log やファイルに書き出す

画面に出せない場面(API のレスポンス、リダイレクトの途中、バッチ処理など)では、ログに書き出すのが確実です。

error_log に書く

<?php
$data = ['id' => 7, 'name' => 'ノート', 'tags' => ['a', 'b'], 'memo' => null, 'on' => false];

ini_set('error_log', __DIR__ . '/app.log');   // 出力先を指定(省略時は php.ini の設定)

error_log(print_r($data, true));
error_log('data=' . var_export($data, true));
error_log('json=' . json_encode($data, JSON_UNESCAPED_UNICODE));

app.log の中身です(時刻は実行時のものです)。

[02-Oct-2026 23:22:14 UTC] Array
(
    [id] => 7
    [name] => ノート
    [tags] => Array
        (
            [0] => a
            [1] => b
        )

    [memo] => 
    [on] => 
)

[02-Oct-2026 23:22:14 UTC] data=array (
  'id' => 7,
  'name' => 'ノート',
  'tags' => 
  array (
    0 => 'a',
    1 => 'b',
  ),
  'memo' => NULL,
  'on' => false,
)
[02-Oct-2026 23:22:14 UTC] json={"id":7,"name":"ノート","tags":["a","b"],"memo":null,"on":false}
書き方 行数 null と false の区別 向いている使い方
print_r($v, true) 多い つかない 形をざっと確認する
var_export($v, true) 多い つく 値を正確に残す
json_encode($v, JSON_UNESCAPED_UNICODE) 1行 つく grep で探す、ログ収集の仕組みに渡す

ログは1件1行のほうが検索しやすいので、長く残すログには json_encode、その場の調査には print_r や var_export と分けると扱いやすくなります。JSON_UNESCAPED_UNICODE をつけないと、日本語は あ のような形式で出力されます。

任意のファイルに追記する

error_log の設定に頼らず、決めたファイルへ書きたいときは file_put_contents を使います。

<?php
$data = ['id' => 7, 'name' => 'ノート'];

file_put_contents(
    __DIR__ . '/debug.log',
    date('[Y-m-d H:i:s] ') . var_export($data, true) . PHP_EOL,
    FILE_APPEND | LOCK_EX
);

// error_log の第2引数に 3 を指定すると、第3引数のファイルへそのまま追記する
error_log("direct\n", 3, __DIR__ . '/direct.log');

debug.log の中身です。

[2026-10-02 23:22:14] array (
  'id' => 7,
  'name' => 'ノート',
)
  • FILE_APPEND をつけると追記 になります。つけないと毎回上書きされます。
  • LOCK_EX をつけると、同時に書き込まれたときに行が混ざりにくく なります。
  • error_log($msg, 3, $file) は日時を自動でつけず、改行も入れません。自分で "\n" を足します。

CLI では標準エラー出力へ書く方法も手軽です。標準出力と分かれるので、コマンドの結果をファイルにリダイレクトしていてもデバッグ表示が混ざりません。

<?php
fwrite(STDERR, print_r(['e' => 1], true));

var_export の出力をPHPコードとして再利用する

var_export の特長は、出力がそのまま有効な PHP コードになる ことです。配列をファイルに保存して、あとで require で読み戻せます。

<?php
$data = ['id' => 7, 'name' => 'ノート', 'tags' => ['a', 'b'], 'memo' => null, 'on' => false];

// 保存
file_put_contents(__DIR__ . '/cache.php', '<?php return ' . var_export($data, true) . ';');

// 読み戻し
$back = require __DIR__ . '/cache.php';
var_dump($back === $data);
bool(true)

=== で比較して true なので、キー・値・型・順番まで完全に元どおり です。設定の配列をキャッシュする、テスト用の期待値をコードに貼る、といった用途に向いています。

オブジェクトを再利用するには __set_state が必要

自作クラスのオブジェクトは \クラス名::__set_state(array(...)) という形で出力されます。これを実行できるようにするには、クラスに静的メソッド __set_state() を用意します。

<?php
class P {
    public $x = 1;
    public static function __set_state(array $a) {
        $p = new self;
        $p->x = $a['x'];
        return $p;
    }
}
$code = var_export(new P, true);
echo $code, "\n";
var_dump(eval("return $code;"));

$code = var_export((object)['a' => 1], true);
echo $code, "\n";
var_dump(eval("return $code;"));
\P::__set_state(array(
   'x' => 1,
))
object(P)#2 (1) {
  ["x"]=>
  int(1)
}
(object) array(
   'a' => 1,
)
object(stdClass)#3 (1) {
  ["a"]=>
  int(1)
}

stdClass は (object) array(...) の形で出力されるので、__set_state() なしで復元できます。この形式になったのは PHP 7.3 からです(PHP公式マニュアルの変更履歴で確認)。なお、ここでは復元を確かめるために eval を使いましたが、eval に渡すのは自分で生成した文字列だけ にします。外部から受け取った文字列を eval に渡すと、意図しないコードが実行されるためです。

値の種類 var_export の出力をコードとして使えるか
null・真偽値・数値・文字列 使える
配列(入れ子を含む) 使える
stdClass 使える(PHP 7.3 以降)
Enum 使える(\Status::Open)
自作クラスのオブジェクト __set_state() を用意すれば使える
クロージャ・リソース 使えない
循環参照を含む値 使えない(次の節)

循環参照を含む変数を表示するとどうなるか

循環参照とは、変数をたどっていくと自分自身に戻ってくる構造 のことです。親と子が互いを指すオブジェクトなどでよく起こります。

<?php
$p = new stdClass;
$c = new stdClass;
$p->child = $c;
$c->parent = $p;   // 子から親へ戻る

print_r($p);
var_dump($p);
var_export($p);

print_r と var_dump の出力です。

stdClass Object
(
    [child] => stdClass Object
        (
            [parent] => stdClass Object
 *RECURSION*
        )

)
object(stdClass)#1 (1) {
  ["child"]=>
  object(stdClass)#2 (1) {
    ["parent"]=>
    *RECURSION*
  }
}

var_export の出力です(Warning のファイルパスは環境に合わせて置き換えています)。

PHP Warning:  var_export does not handle circular references in /home/taro/app/b.php on line 9
(object) array(
   'child' => 
  (object) array(
     'parent' => NULL,
  ),
)

配列が自分自身を参照する場合も同じ結果になります。

<?php
$a = ['id' => 1];
$a['self'] = &$a;
print_r($a);
Array
(
    [id] => 1
    [self] => Array
 *RECURSION*
)
関数 循環参照を渡したとき(PHP 8.4.21 で実行)
print_r *RECURSION* と表示して続行する
var_dump *RECURSION* と表示して続行する
var_export Warning: var_export does not handle circular references を出し、該当箇所を NULL にする
json_encode false を返す。json_last_error_msg() は Recursion detected
json_encode(JSON_THROW_ON_ERROR つき) JsonException: Recursion detected を投げる
json_encode(JSON_PARTIAL_OUTPUT_ON_ERROR つき) {"child":{"parent":null}} と、該当箇所を null にして出力する
serialize 参照を保ったまま文字列にできる

循環参照を含む変数を調べるときは print_r か var_dump を使う と、止まらずに全体を確認できます。循環した構造を保存して復元したいときは serialize が向いています。

<?php
$s = serialize($p);
echo $s, "\n";
$q = unserialize($s);
var_dump($q->child->parent === $q);
O:8:"stdClass":1:{s:5:"child";O:8:"stdClass":1:{s:6:"parent";r:1;}}
bool(true)

r:1 が「1番目の値への参照」を表していて、復元後も親子が同じインスタンスを指しています。

json_encode で表示するときの違い

json_encode は本来データ交換用ですが、デバッグ表示としても便利です。

<?php
$data = ['id' => 7, 'name' => 'ノート', 'tags' => ['a', 'b'], 'memo' => null, 'on' => false];
echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE), "\n";
{
    "id": 7,
    "name": "ノート",
    "tags": [
        "a",
        "b"
    ],
    "memo": null,
    "on": false
}

知っておくとよい違いは次の3つです。

<?php
class U { public $n = 'a'; private $p = 'b'; protected $q = 'c'; }
echo json_encode(new U), "\n";
echo json_encode(['f' => 1.0, 's' => 'あ']), "\n";
{"n":"a"}
{"f":1,"s":"あ"}
  • オブジェクトは public プロパティだけ が出力されます。private・protected を見たいときは var_dump か print_r を使います。
  • 小数の 1.0 は 1 と出力され、整数と見分けられません。
  • 日本語は JSON_UNESCAPED_UNICODE をつけるとそのまま出力されます。

ブラウザの開発者ツールで見たいときは、JavaScript の console.log に渡す方法もあります。次のコードは書き方の例で、ブラウザでの表示は今回は未実行です。

<?php
$data = ['id' => 7, 'name' => 'ノート'];
$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
echo "<script>console.log($json);</script>";

JSON_HEX_TAG などをつけておくと、値に </script> のような文字列が含まれていても HTML が崩れません。

debug_zval_dump で参照カウントを見る

変数がいくつの場所から参照されているか(参照カウント)まで見たいときは、debug_zval_dump を使います。参照カウントを表示する組み込み関数は debug_zval_dump です。

<?php
$a = ['x' => rand()];
debug_zval_dump($a);
$b = $a;              // コピー(実際には同じ配列を共有する)
debug_zval_dump($a);

$o = new stdClass;
$o2 = $o;
debug_zval_dump($o);
array(1) refcount(2){
  ["x"]=>
  int(1850802632)
}
array(1) refcount(3){
  ["x"]=>
  int(1850802632)
}
object(stdClass)#1 (0) refcount(3){
}
  • $b = $a と代入しただけでは配列はコピーされず、同じ実体を共有 します(どちらかを書き換えたときに初めてコピーされる、コピーオンライトという仕組みです)。代入後に refcount が 1 増えているのがその証拠です。
  • 表示される数は、debug_zval_dump に引数として渡したぶんの 1 が加わった値です。
  • 整数のようにカウントを持たない値では refcount は表示されず、ソースコードに直接書いた文字列は interned と表示されます(debug_zval_dump(1, 'lit') の出力は int(1) と string(3) "lit" interned でした)。

ふだんの調査は var_dump で足ります。メモリの使われ方や参照の共有を調べるときだけ debug_zval_dump を使う、という位置づけです。

Xdebug を入れると var_dump の表示が変わる

開発環境に Xdebug が入っていると、var_dump の見た目が変わります。今回の検証環境には Xdebug を導入できなかったため、この節の内容は Xdebug 公式ドキュメント(Development Helpers のページ)で確認したもので、表示そのものは未実行 です。

項目 内容(Xdebug 公式ドキュメントで確認)
有効になる条件 xdebug.mode=develop のとき
ブラウザでの表示 html_errors が 1 のとき、HTML で整形され、型ごとに色がつく
追加される情報 var_dump を呼んだファイルと行
xdebug.var_display_max_depth 入れ子を表示する深さ。既定値 3
xdebug.var_display_max_children 配列の要素・プロパティを表示する数。既定値 128
xdebug.var_display_max_data 文字列を表示する長さ。既定値 512
関連する関数 xdebug_var_dump()、参照カウントを表示する xdebug_debug_zval()

つまずきやすいのは次の2点です。

  • 深い配列が途中で省略されて見える ときは、xdebug.var_display_max_depth の既定値 3 が効いています。php.ini で値を大きくするか、print_r や var_export に切り替えると全体を確認できます。
  • Xdebug が HTML で整形してくれる環境では、pre タグで囲む必要がありません。 逆に、Xdebug のない環境(本番に近いサーバーなど)へ持っていくと1行につながって見えるので、その場合は前述の pre タグ整形を使います。

なお、Xdebug のない PHP 8.4.21 の CLI では、html_errors を 1 に変更しても var_dump の出力はプレーンテキストのままでした。

dump() と dd() との使い分け

Laravel や Symfony を使っている場合は、dump() と dd() が使えます。どちらも Symfony の VarDumper コンポーネントが提供する機能です。今回の検証環境ではパッケージを取得できなかったため、この節は一般に知られた仕様の整理で、未実行 です。

関数 動き 向いている場面
dump($v) 整形して表示し、処理を続ける 途中の値を何か所か見たい
dd($v) 整形して表示し、そこで処理を終了する その時点の値だけ見たい
var_dump($v) そのまま表示し、処理を続ける フレームワークなしで型を確認したい

dump() はブラウザで折りたたみ表示ができ、CLI では色つきで表示されます。フレームワークが入っているなら dump() / dd() が見やすく、素の PHP や、ライブラリを追加できない環境では var_dump・print_r・var_export の3つ が頼りになります。3つの関数は PHP に最初から入っているので、どの環境でも同じように使えるのが強みです。

目的別の選び方

やりたいこと 選ぶもの 書き方
型まで正確に知りたい var_dump var_dump($v);
配列の形をざっと見たい print_r print_r($v);
ブラウザで崩さず見たい print_r と pre echo '<pre>' . htmlspecialchars(print_r($v, true)) . '</pre>';
複数の変数を一度に見たい var_dump var_dump($a, $b, $c);
ログに1行で残したい json_encode error_log(json_encode($v, JSON_UNESCAPED_UNICODE));
ログに読みやすく残したい print_r error_log(print_r($v, true));
var_dump の結果を文字列にしたい ob_start ob_start(); var_dump($v); $s = ob_get_clean();
あとでコードに貼りたい var_export var_export($v);
配列をファイルに保存して読み戻したい var_export '<?php return ' . var_export($v, true) . ';'
private プロパティを見たい var_dump か print_r var_dump($obj);
循環参照のある変数を見たい var_dump か print_r var_dump($obj);
参照カウントを見たい debug_zval_dump debug_zval_dump($v);
伏せたい値を隠して表示したい __debugInfo() と var_dump クラスにメソッドを追加

つまずきやすい点と直し方

起きること 原因 こうするとよい
print_r で何も表示されない 値が null・false・空文字のいずれか var_dump で型を確認する
ブラウザで1行につながって見える HTML では改行がまとめられる pre タグで囲む
表示が途中で切れたり崩れたりする 値に HTML タグが含まれている htmlspecialchars を通す
$s = var_dump($v); で $s が NULL var_dump は文字列を返さない ob_start と ob_get_clean を使う
深い配列が省略される Xdebug の表示上限 xdebug.var_display_max_depth を上げる、または print_r
var_export で Warning が出る 循環参照がある print_r か var_dump、保存なら serialize
json_encode が false を返す 循環参照などエンコードできない値がある json_last_error_msg() で理由を見る
日本語が あ のようになる json_encode の既定の動き JSON_UNESCAPED_UNICODE をつける
API のレスポンスが壊れる デバッグ出力が JSON に混ざった error_log へ書き出す
ログファイルが毎回上書きされる FILE_APPEND がついていない FILE_APPEND と LOCK_EX を指定する

デバッグ出力を残さないためのチェックリスト

  • [ ] 公開前に var_dump(、print_r(、var_export(、dd(、dump( を検索して確認した
  • [ ] 画面に出す代わりに error_log を使える箇所は置き換えた
  • [ ] ログに書く値に、パスワードやトークンが含まれていない
  • [ ] 伏せたい値を持つクラスには __debugInfo() を用意した
  • [ ] デバッグ用の関数(d() など)は1か所に定義し、呼び出しを検索しやすくした

よくある質問

Q. print_r で配列が1行で表示されてしまいます。どうすれば見やすくなりますか? A. ブラウザでは改行がまとめて扱われるためです。echo '<pre>' . htmlspecialchars(print_r($v, true), ENT_QUOTES, 'UTF-8') . '</pre>'; のように pre タグで囲むと、改行とインデントがそのまま表示されます。ブラウザの「ページのソースを表示」で見ても改行された状態を確認できます。

Q. var_dump の結果を変数に入れるにはどうすればよいですか? A. var_dump は文字列を返さないので、ob_start(); var_dump($v); $s = ob_get_clean(); と出力バッファで受け取ります。print_r と var_export は第2引数に true を渡すだけで文字列が返ります。

Q. var_export と serialize はどう使い分けますか? A. var_export は人が読めて編集もできる PHP コードになるので、設定の配列やテストデータに向いています。serialize は人には読みにくいものの、循環参照やオブジェクトの状態をそのまま保存できます。どちらも、復元するときは自分で保存したデータだけを対象にします。

Q. string(9) "ノート" の 9 は何の数字ですか? A. バイト数です。UTF-8 では日本語1文字が3バイトなので、3文字で 9 になります。文字数を知りたいときは mb_strlen() を使います。

まとめ

  • var_dump は型と長さまで表示 するので、null・false・0・空文字・'0' を確実に見分けられる
  • print_r は短く読みやすい 一方、null・false・空文字はどれも空で表示される
  • var_export は PHP コードとして再利用できる。配列をファイルに保存して require で読み戻すと === で一致する
  • 文字列で受け取るには、print_r と var_export は第2引数 true、var_dump は ob_start を使う
  • ブラウザでは pre タグと htmlspecialchars、画面に出せない場面では error_log や file_put_contents に書き出す
  • 循環参照は print_r と var_dump なら *RECURSION* と表示して続行、var_export は Warning、json_encode は false になる
  • Xdebug があると var_dump が整形され、深さ3で省略される。dump() / dd() はフレームワーク利用時の選択肢

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「PHP var_dump・print_r・var_exportの違いと配列表示」

株式会社RJCでは、PHPのデバッグ出力の使い分けを仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?