# sebastian/exporter: Human-Readable PHP Variable Output for Test Diagnostics

> sebastian/exporter is a PHP library that converts any variable into a formatted string representation, handling arrays, objects, circular references, and binary strings in a way that var_dump does not. It is part of the PHPUnit ecosystem and is most useful in test frameworks that need to print failure diffs.

**sebastianbergmann/exporter** — Provides the functionality to export PHP variables for visualization

- Repository: https://github.com/sebastianbergmann/exporter
- Stars: 6,809 · Forks: 40
- Language: PHP
- License: BSD-3-Clause
- Published: 2026-09-22 · Updated: 2026-09-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/sebastianbergmann-exporter

## The Problem: var_dump Is Not Enough for Test Failures

PHP's built-in var_dump prints variable contents, but its output format is fixed, it handles circular references by printing them indefinitely until memory runs out, and it gives no compact option for large data structures. In test frameworks, failure messages need to print expected and actual values side by side in a way a developer can scan quickly. sebastian/exporter was written to fill that gap.

The library provides two main output modes. The full export mode renders every detail: array reference markers, object instance identifiers, property values, and a special notation for binary strings. The shortened export mode collapses large arrays to [...] and long strings to a prefix and suffix with an ellipsis, keeping failure messages compact.

The library is part of Sebastian Bergmann's ecosystem of PHPUnit support components and is released under the BSD-3-Clause license. The most recent releases are 8.2.1 and 8.2.0, both from 2026-08-07, and the last push to the repository was on 2026-09-26.

## Installing via Composer

The library is distributed through Packagist as sebastian/exporter. For projects that need it at runtime:

```bash
composer require sebastian/exporter
```

For projects that only need it during testing:

```bash
composer require --dev sebastian/exporter
```

The README recommends the --dev flag for test suites. Composer resolves the package version constraint and places the library in vendor/. No further configuration is needed; the Exporter class is available through the SebastianBergmann\Exporter namespace once the autoloader is included.

## Exporting Simple and Complex PHP Types

The Exporter class handles every PHP primitive and converts each to a predictable string. Integers and floats render as their literal values, strings are quoted, booleans render as true or false, null renders as null, NAN and negative infinity render as NAN and -INF respectively, and resources render as resource(N) of type (stream) or similar.

For arrays, the library assigns reference markers:

```php
<?php declare(strict_types=1);
use SebastianBergmann\Exporter\Exporter;

$exporter = new Exporter;
print $exporter->export([[1, 2, 3], ['', 0, false]]);
```

This prints output where each array is labeled with a reference number like Array &0, Array &1, so the reader can track which nested arrays are shared. The same mechanism applies to objects: each object instance gets an identifier such as stdClass Object #4, and subsequent occurrences of the same instance are printed as a reference rather than re-expanded.

## Circular References and the Reference Tracking Mechanism

One of the practical reasons to use this library over var_dump is its handling of circular references. When an array contains a reference to itself, or an object holds a reference to itself, var_dump enters an infinite loop. sebastian/exporter tracks which arrays and objects it has already visited using the ExportContext, and replaces re-encountered values with a back-reference notation.

For example, a self-referencing array prints as:

```php
<?php declare(strict_types=1);
use SebastianBergmann\Exporter\Exporter;

$array         = [];
$array['self'] = &$array;
print $exporter->export($array);
```

The output labels the inner self entry with Array &1 to match the outer array's reference identifier, making the cycle visible without looping. The same logic applies when a custom ObjectExporter is used: passing the ExportContext through nested exports ensures that reference tracking remains consistent across the entire output.

## Custom Object Rendering with ObjectExporter

By default, objects are exported property by property using reflection. For domain objects with a meaningful string representation, this default is often too verbose. The library provides an ObjectExporter interface with two methods: handles(object $object): bool to declare which classes the exporter covers, and export(...): string to produce the representation.

Registering a custom exporter requires passing it to the Exporter constructor:

```php
<?php declare(strict_types=1);
use SebastianBergmann\Exporter\Exporter;

$exporter = new Exporter(objectExporter: new MoneyExporter);
print $exporter->export(new Money(1999, 'EUR'));
```

For projects with multiple domain types, ObjectExporterChain composes several exporters into one. Each is consulted in order; the first one whose handles() method returns true produces the output. Enums are treated as objects and are therefore passed to the exporter chain as well.

## Where sebastian/exporter Falls Short

The library is designed for human-readable diagnostic output, not for serialization. The strings it produces cannot be parsed back into PHP values. It is not a replacement for serialize(), json_encode(), or a proper data mapper.

The shortened export mode collapses content aggressively: any array with more than five elements becomes [...], and strings beyond a certain length are truncated. This is intentional for keeping test output compact, but it means the shortened format loses information and is unsuitable for detailed inspection.

The library also does not produce output compatible with var_export(), which generates valid PHP syntax. If a project needs to snapshot a value and later eval() it back, this library is not the right tool.

The ObjectExporter interface is powerful, but it places full responsibility on the implementor. An object exporter that calls back into the main Exporter without passing the ExportContext through correctly will produce export output where reference numbering restarts from scratch for nested values, breaking the reference tracking for the entire export tree. The README documents this requirement explicitly, calling out the need to pass the ExportContext argument when exporting nested values.

Additionally, the README does not document thread safety or behavior under concurrent access. The library is stateless aside from the ExportContext passed during a single export call, but teams using shared state in unusual ways should verify behavior themselves.

## sebastian/exporter vs. var_dump and Symfony VarDumper

PHP's var_dump is available everywhere without installation but offers no circular reference protection, no compact mode, and no way to redirect output to a string without output buffering. It is adequate for quick inspection but awkward inside test assertions.

Symfony's VarDumper component is a more feature-rich alternative. It produces HTML output for browser contexts, colors for CLI, handles circular references, and supports casters (analogous to ObjectExporter) for custom types. VarDumper is designed for interactive debugging, while sebastian/exporter targets programmatic output inside a framework. VarDumper carries the full Symfony component dependency, while sebastian/exporter is a standalone library with no external runtime dependencies beyond PHP itself.

For teams already using PHPUnit, sebastian/exporter is already present transitively. For teams building a custom test reporter or a diff-based assertion outside PHPUnit, the choice between VarDumper's richer formatting and sebastian/exporter's lighter footprint depends on whether interactive debugging features are needed.

## Conclusion

sebastian/exporter is the right choice when you need consistent, readable variable output inside a PHP test framework or diagnostic tool, especially if you need custom rendering for domain objects via the ObjectExporter interface. It is not a general-purpose debugging replacement for Xdebug or a structured data serializer; if you need round-trip serialization or machine-readable output, this library is the wrong tool. Before adopting it as a standalone dependency, check whether PHPUnit is already in your project, since PHPUnit pulls in sebastian/exporter transitively.

## FAQ

### How do I install sebastian/exporter in a PHP project?

Run composer require --dev sebastian/exporter to add it as a development dependency. The Exporter class is then available in the SebastianBergmann\Exporter namespace through Composer's autoloader.

### Does sebastian/exporter handle circular references in arrays and objects?

Yes. The library tracks all visited arrays and objects via an ExportContext and replaces re-encountered values with a reference marker, preventing infinite recursion. The reference identifiers (such as Array &1) appear in the output to make the circular structure visible.

### Can I customize how specific object types are rendered?

Yes. Implement the ObjectExporter interface and pass an instance to the Exporter constructor. For multiple types, wrap several ObjectExporter implementations in an ObjectExporterChain, which consults them in order and uses the first one whose handles() method returns true.

## Sources

- [Issues](https://github.com/sebastianbergmann/exporter/issues)
- [License: BSD-3-Clause](https://github.com/sebastianbergmann/exporter/blob/main/LICENSE)
- [README](https://github.com/sebastianbergmann/exporter/blob/main/README.md)
- [Releases](https://github.com/sebastianbergmann/exporter/releases)
- [sebastianbergmann/exporter on GitHub](https://github.com/sebastianbergmann/exporter)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/sebastianbergmann-exporter
