In PHP, how does var_export() let you cache a computed tariff table as a PHP file, and which values can it not export?
answer
- returns code when the second argument is true
- <?php return ...; then require
- stdClass as (object) array
- __set_state for other objects
- circular references become NULL
basics
~20 svar_export($value, true) returns PHP source for the value; write '<?php return ' . that . ';' to a file and require it later. Scalars, arrays, stdClass and enums work; cycles and resources do not, and other objects need __set_state().
solid answer
~40 s`var_export($value, true)` returns a **string of PHP code** that evaluates to the value (without `true` it prints and returns `null`). Writing `'<?php return ' . var_export($table, true) . ';'` to a file and later doing `$table = require $file;` turns the cache into ordinary compiled PHP, with no parser of its own. Scalars, `null`, arrays, `stdClass` (exported as `(object) array(...)`) and enum cases (exported as `\Enum::Case`) round-trip directly. Any other object is exported as `\Class::__set_state(array(...))`, which only loads if the class defines `__set_state()`. **Circular references** produce `NULL` plus a warning, and **resources** become `NULL`. Since PHP 8.2, exported class names are fully qualified with a leading backslash.
code
php · 14 lines<?php
declare(strict_types=1);
$cacheFile = __DIR__ . '/var/cache/tariffs.php';
$table = ['EU' => ['A' => 0.19, 'B' => 0.07], 'UK' => ['A' => 0.2]];
$code = '<?php return ' . var_export($table, true) . ";\n";
$tmp = $cacheFile . '.' . bin2hex(random_bytes(4));
file_put_contents($tmp, $code);
rename($tmp, $cacheFile); // readers see the old or the new file, never half of one
// A later request:
$table = require $cacheFile;
echo $table['EU']['B']; // 0.07go deeper
Remember the second argument: var_export($v, true) returns the PHP code as a string instead of printing it to output.
Explain the '<?php return ...;' plus require pattern, what stdClass, enums and other objects export as, and the circular-reference limit.
Build the cache file safely: temporary file and rename, arrays rather than objects, and a cache directory no untrusted process can write to.
Decide when generated PHP files beat an external cache for read-mostly data, weighing deploy-time generation, invalidation and file permissions.
## What var_export() is `var_export(mixed $value, bool $return = false): ?string` produces a representation of a value that is **valid PHP code**. With `$return` left at `false` it prints the code and returns `null`; with `true` it returns the code as a string. That second form is what makes it useful beyond debugging. ## The cache-file pattern Suppose each request needs a tariff table that is expensive to compute from rules in a database. Computing it on every request is wasteful. One option is to compute it once and write it out as PHP: 1. Build the array: region, band, rate. 2. Generate the source: `'<?php return ' . var_export($table, true) . ';' . "\n"`. 3. Write it to a temporary file in the cache directory, then rename it over the real path, so no request ever includes a half-written file. 4. In later requests, `$table = require $cacheFile;` returns the array. The loaded file is **ordinary PHP**, so it is compiled like any other script and needs no decode step of its own. That is the reason frameworks use the same trick for compiled configuration and routes. How PHP's opcode cache then keeps such files in shared memory is a performance topic of its own. ## What it exports, and how | Value | Exported as | Loads back? | |---|---|---| | int, float, string, bool, null | literals: `42`, `0.19`, `'EU'`, `true`, `NULL` | yes | | array | `array ( 'EU' => array ( ... ), )` | yes | | `stdClass` | `(object) array( ... )` | yes, since 7.3 | | enum case | `\Suit::Hearts` | yes | | any other object | `\App\Tariff::__set_state(array( ... ))` | only if the class defines `__set_state()` | | resource | `NULL` | no, the value is lost | | array or object containing itself | `NULL` plus `E_WARNING` "var_export does not handle circular references" | no | Notes on the table: - **Strings** are written with single quotes and escaped, so arbitrary text round-trips safely. - **Class names** have been fully qualified, with a leading backslash, since PHP 8.2. Before that, a namespaced class was exported without it, which broke when the generated file declared its own namespace. - **`__set_state()`** is not called at export time. `var_export()` only writes the call; the method runs when the file is included. A class without it fails at load time with a call to an undefined method, not at export time. ## What the generated file looks like For `['EU' => ['A' => 0.19]]`, `var_export()` produces: ```php array ( 'EU' => array ( 'A' => 0.19, ), ) ``` The output is stable for the same input, so a generated cache file can be committed or diffed between builds, and a reviewer can read it without a decoder. ## var_export() versus serialize() for this job - **`var_export()`** output is human-readable, diffable and plain PHP. It suits data made of arrays and scalars, which is exactly the shape a precomputed lookup table should have. - **`serialize()`** handles any object graph, private state and references, but reading it back needs `unserialize()` on every request, and it carries the class-coupling issues of serialized objects. - Neither is a place for data an outsider can influence: an included file is **executable code**, so the cache directory must be writable only by the deploy or build process and the application user, never by uploads. ## Pitfalls worth naming - Forgetting the second argument: the table is printed into the response and `null` is written to the file. - Forgetting the trailing `;` after the exported expression, which leaves a parse error in the cache file. - Writing the file in place instead of via a temporary file and a rename, so a concurrent request includes a truncated file. - Exporting value objects instead of arrays and then discovering at load time that the class has no `__set_state()`.
- What happens if you var_export() an object of your own class and later require the file?The export itself succeeds and writes `\YourClass::__set_state(array(...))`. When the file is required, PHP calls that static method; if the class does not define `__set_state()`, the include fails with an `Error` for calling an undefined method. Export arrays, or add `__set_state()` deliberately.
- Why does var_export() return NULL for an array that contains a reference to itself?Valid PHP code cannot express a structure that contains itself as a literal. When `var_export()` detects the recursion it writes `NULL` in that position and emits the `E_WARNING` "var_export does not handle circular references". `serialize()` can represent such graphs with back-references.
saying these in an interview costs you the question
- var_export() returns the code as a string even without a second argument
- var_export() calls __set_state() on each object while exporting
- var_export() can export any object graph, including circular ones
- Writing the cache file in place is safe because writes are atomic
- var_export() output is JSON-compatible