In PHP, how do var_dump(), print_r() and var_export() differ, and when would you use each one?
answer
- types and lengths vs readable vs code
- var_dump has no return option
- print_r shows false and null as empty
- var_export output is valid PHP
- recursion: marker vs warning
basics
~20 svar_dump() prints types, lengths and values and cannot return a string. print_r() prints a readable view, hides types, and can return a string. var_export() prints valid PHP code, can return it, and rejects circular references.
solid answer
~40 s`var_dump()` prints **type and value** for each argument, such as `string(4) "Soup"`, `bool(false)`, `NULL`, `float(9.5)`; it takes several values and returns nothing, so capturing it needs output buffering. `print_r()` prints a **human-readable** structure without types: `false` and `null` both appear as an empty string and `true` as `1`, so it hides exactly the bugs you debug. Its second argument `true` makes it **return** the string. `var_export()` prints **valid PHP code** (`false`, `NULL`, `'Soup'`, `array (...)`), can also return it, and exports objects as `\Class::__set_state(array(...))` and enums as `\Menu::Starter`. On a circular reference `var_dump()` and `print_r()` print `*RECURSION*`, while `var_export()` emits `NULL` and a warning. Use `var_dump()` for debugging, `print_r(..., true)` for quick logs, `var_export()` when you need code.
code
php · 13 lines<?php
declare(strict_types=1);
enum Menu { case Starter; case Main; }
$dish = ['name' => 'Soup', 'price' => 9.5, 'vegan' => false, 'note' => null, 'course' => Menu::Starter];
var_dump($dish['vegan'], $dish['note']); // bool(false) NULL
print_r($dish); // [vegan] => , [note] => , [course] => Menu Enum ( ... )
var_export($dish['course']); // \Menu::Starter
echo PHP_EOL, var_export(1.0, true); // 1.0
$log = print_r($dish, true); // captured as a stringgo deeper
Recall that var_dump shows types, print_r is the readable view, and var_export prints PHP code.
Explain which ones can return a string, why print_r hides false and null, and how each handles objects, enums and recursion.
Choose the right dump for logs and fixtures, and keep dumps of objects with credentials out of logs and responses.
Replace ad-hoc dumps in production code with structured logging and a debugger, and keep dump calls out of committed code with a static-analysis rule.
## Three dump functions, three purposes PHP ships three functions that turn a value into text. They look alike but answer different questions: | | `var_dump()` | `print_r()` | `var_export()` | |---|---|---|---| | Signature | `var_dump(mixed $value, mixed ...$values): void` | `print_r(mixed $value, bool $return = false): string\|true` | `var_export(mixed $value, bool $return = false): ?string` | | Shows types | yes | no | implicitly, as PHP literals | | Can return a string | no | yes, with `true` | yes, with `true` | | Several values per call | yes | no | no | | Output is valid PHP | no | no | yes | | Circular reference | prints `*RECURSION*` | prints `*RECURSION*` | prints `NULL`, raises `E_WARNING` | All three show protected and private properties of objects; none shows static properties. ## var_dump(): the debugging view `var_dump()` prints the type of every value, the length of every string and the count of every array: - `bool(false)`, `NULL`, `int(12)`, `float(9.5)`, `string(4) "Soup"` - `array(2) { ... }`, `object(Dish)#3 (2) { ... }` - enums as `enum(Menu::Starter)` That is why it is the default debugging tool: it distinguishes `""`, `null`, `false` and `"0"`, which all look the same elsewhere. Floats are printed with `serialize_precision` (default `-1`, the shortest representation that round-trips). It returns nothing, so to capture the text you wrap it in output buffering. ## print_r(): the readable view `print_r()` is meant for humans reading nested arrays: ``` Array ( [starter] => Soup [vegetarian] => 1 ) ``` For scalars it prints the string conversion of the value. That is its weakness: 1. `true` prints as `1`. 2. `false` and `null` print as **nothing**. 3. `"1"` and `1` look identical. Its strength is the `$return` parameter: `error_log(print_r($order, true))` writes a readable structure to the log. Without `true` it prints and returns `true`. ## var_export(): the code view `var_export()` produces text that PHP can parse back: - scalars as literals: `false`, `true`, `NULL`, `12`, `9.5`, `'Soup'` (floats keep a fraction, so `1.0` stays `1.0`); - arrays in the `array ( 0 => 'a', )` form; - `stdClass` as `(object) array( ... )`; - enums as `\Menu::Starter`; - other objects as `\Dish::__set_state(array( ... ))`, which only works when the class defines a static `__set_state()` method. Since PHP 8.2 class names are fully qualified with a leading backslash. It cannot represent circular structures: it prints `NULL` in their place and raises the warning "var_export does not handle circular references". Resources are exported as `NULL`. ## Reading var_dump() output A few details of the format are worth knowing: - `string(5) "Café"`: the number is the length in **bytes**, not characters. `é` is two bytes in UTF-8, so the count exposes encoding problems. - `object(Dish)#3 (2)`: the class, the object handle number and the number of properties. Two variables showing the same handle refer to the same object. - `["price":protected]` and `["secret":"Dish":private]`: visibility is shown per property. - Several arguments are dumped one after another: `var_dump($a, $b)`. ## Choosing - **Debugging a value's type**: `var_dump()`, because `print_r()` hides `false`, `null` and the difference between `1` and `"1"`. - **Logging a readable structure**: `print_r($value, true)` or `var_export($value, true)`. - **Writing a value as PHP source**, for a fixture or a generated config file: `var_export()`. - **Never in production responses**: all three can print private properties and secrets. Customising what they show for an object is done with a magic method, a topic of its own.
- How do you capture var_dump() output in a string?`var_dump()` has no return parameter, so wrap it in output buffering: `ob_start(); var_dump($x); $text = ob_get_clean();`. For many cases `var_export($x, true)` or `print_r($x, true)` is simpler, but only `var_dump()` shows string lengths and distinguishes every type.
- What does print_r() print for false and for null, and why does that matter?An empty string for both, because `print_r()` prints the string conversion of scalars; `true` prints as `1`. When you are debugging why a condition failed, that output cannot tell `false`, `null` and `""` apart, which is why `var_dump()` is the tool for type questions.
saying these in an interview costs you the question
- print_r() shows the type of every value.
- var_dump() has a second parameter that returns the output as a string.
- var_export() handles circular references like serialize() does.
- print_r(false) prints the word false.
- Dump output is safe to show to users because private properties are hidden.