PHPackages                             francislavoie/varexporter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. francislavoie/varexporter

AbandonedArchivedLibrary[Utility &amp; Helpers](/categories/utility)

francislavoie/varexporter
=========================

A powerful alternative to var\_export(), which can export closures and objects without \_\_set\_state()

0.2.3(6y ago)015[1 PRs](https://github.com/Vectorface/varexporter/pulls)MITPHPPHP &gt;=7.0

Since Aug 29Pushed 1y agoCompare

[ Source](https://github.com/Vectorface/varexporter)[ Packagist](https://packagist.org/packages/francislavoie/varexporter)[ RSS](/packages/francislavoie-varexporter/feed)WikiDiscussions master Synced 2mo ago

READMEChangelogDependencies (3)Versions (3)Used By (0)

Vectorface\\VarExporter
=======================

[](#vectorfacevarexporter)

[![](https://raw.githubusercontent.com/brick/brick/master/logo.png)](https://raw.githubusercontent.com/brick/brick/master/logo.png)

A powerful and pretty replacement for PHP's `var_export()`.

[![Build Status](https://camo.githubusercontent.com/57569d31c8504cfbbf4591223b9c3ff3302d090b8f9d88fbeefa66086862cdeb/68747470733a2f2f7365637572652e7472617669732d63692e6f72672f627269636b2f7661726578706f727465722e7376673f6272616e63683d6d6173746572)](http://travis-ci.org/vectorface/varexporter)[![Coverage Status](https://camo.githubusercontent.com/a37977961c423d9dcb38d7cdd1bd259a36ba71e781b67c068cf9372892e3a3bc/68747470733a2f2f636f766572616c6c732e696f2f7265706f732f627269636b2f7661726578706f727465722f62616467652e7376673f6272616e63683d6d6173746572)](https://coveralls.io/r/vectorface/varexporter?branch=master)[![Latest Stable Version](https://camo.githubusercontent.com/7a6cd3644b812ce6ed15076f4e05c90bc2dc6ff6386f769f8dc84b640b927eb8/68747470733a2f2f706f7365722e707567782e6f72672f627269636b2f7661726578706f727465722f762f737461626c65)](https://packagist.org/packages/vectorface/varexporter)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](http://opensource.org/licenses/MIT)

Note
----

[](#note)

This is just a quick fork of  to add PHP 7.0 support for some legacy apps.

Introduction
------------

[](#introduction)

PHP's [var\_export()](https://www.php.net/manual/en/function.var-export.php) function is a handy way to export a variable as executable PHP code.

It is particularly useful to store data that can be cached by OPCache, just like your source code, and later retrieved very fast, much faster than unserializing data using `unserialize()` or `json_decode()`.

But it also suffers from several drawbacks:

- It outputs invalid PHP code for `stdClass` objects, using `stdClass::__set_state()` which doesn't exist (PHP &lt; 7.3)
- It cannot export custom objects that do not implement `__set_state()`, and `__set_state()` does not play well with private properties in parent classes, which makes the implementation tedious
- It does not support closures

Additionally, the output is not very pretty:

- It outputs arrays as `array()` notation, instead of the short `[]` notation
- It outputs numeric arrays with explicit and unnecessary `0 => ...` key =&gt; value syntax

This library aims to provide a prettier, safer, and powerful alternative to `var_export()`.

### Installation

[](#installation)

This library is installable via [Composer](https://getcomposer.org/):

```
composer require vectorface/varexporter-legacy
```

### Requirements

[](#requirements)

This library requires PHP 7.0 or later.

### Project status &amp; release process

[](#project-status--release-process)

While this library is still under development, it is well tested and should be stable enough to use in production environments.

The current releases are numbered `0.x.y`. When a non-breaking change is introduced (adding new methods, optimizing existing code, etc.), `y` is incremented.

**When a breaking change is introduced, a new `0.x` version cycle is always started.**

It is therefore safe to lock your project to a given release cycle, such as `0.2.*`.

If you need to upgrade to a newer release cycle, check the [release history](https://github.com/vectorface/varexporter/releases) for a list of changes introduced by each further `0.x.0` version.

Quickstart
----------

[](#quickstart)

This library offers a single method, `VarExporter::export()` which works pretty much like `var_export()`:

```
use Brick\VarExporter\VarExporter;

echo VarExporter::export([1, 2, ['foo' => 'bar', 'baz' => []]]);
```

This code will output:

```
[
    1,
    2,
    [
        'foo' => 'bar',
        'baz' => []
    ]
]
```

Compare this to the `var_export()` output:

```
array (
  0 => 1,
  1 => 2,
  2 =>
  array (
    'foo' => 'bar',
    'baz' =>
    array (
    ),
  ),
)
```

Note: unlike `var_export()`, `export()` always returns the exported variable, and never outputs it.

Exporting stdClass objects
--------------------------

[](#exporting-stdclass-objects)

You come across a `stdClass` object every time you cast an array to an object, or use `json_decode()` with the second argument set to `false` (which is the default).

While the output of `var_export()` for `stdClass` is syntactically valid PHP code:

```
var_export(json_decode('
    {
        "foo": "bar",
        "baz": {
            "hello": "world"
        }
    }
'));
```

```
stdClass::__set_state(array(
   'foo' => 'bar',
   'baz' =>
  stdClass::__set_state(array(
     'hello' => 'world',
  )),
))
```

it is totally useless as it assumes that `stdClass` has a static `__set_state()` method, when it doesn't:

> Error: Call to undefined method stdClass::\_\_set\_state()

### What does `VarExporter` do instead?

[](#what-does-varexporter-do-instead)

It outputs an array to object cast, which is syntactically valid, readable **and** executable:

```
echo VarExporter::export(json_decode('
    {
        "foo": "bar",
        "baz": {
            "hello": "world"
        }
    }
'));
```

```
(object) [
    'foo' => 'bar',
    'baz' => (object) [
        'hello' => 'world'
    ]
]
```

**Note: since PHP 7.3, `var_export()` now exports an array to object cast like `VarExporter::export()` does.**

Exporting custom objects
------------------------

[](#exporting-custom-objects)

As we've seen above, `var_export()` assumes that every object has a static [\_\_set\_state()](https://www.php.net/manual/en/language.oop5.magic.php#object.set-state) method that takes an associative array of property names to values, and returns a object.

This means that if you want to export an instance of a class outside of your control, you're screwed up. This also means that you have to write boilerplate code for your classes, that looks like:

```
class Foo
{
    public $a;
    public $b;
    public $c;

    public static function __set_state(array $array) : self
    {
        $object = new self;

        $object->a = $array['a'];
        $object->b = $array['b'];
        $object->c = $array['c'];

        return $object;
    }
}
```

Or the more dynamic, reusable, and less IDE-friendly version:

```
public static function __set_state(array $array) : self
{
    $object = new self;

    foreach ($array as $key => $value) {
        $object->{$key} = $value;
    }

    return $object;
}
```

If your class has a parent with private properties, you may have to do some gymnastics to write the value, and if your class overrides a private property of one of its parents, you're out of luck as `var_export()` puts all properties in the same bag, outputting an array with a duplicate key.

### What does `VarExporter` do instead?

[](#what-does-varexporter-do-instead-1)

It determines the most appropriate method to export your object, in this order:

- If your custom class has a `__set_state()` method, `VarExporter` uses it by default, just like `var_export()` would do:

    ```
    \My\CustomClass::__set_state([
        'foo' => 'Hello',
        'bar' => 'World'
    ])
    ```

    The array passed to `__set_state()` will be built with the same semantics used by `var_export()`; this library aims to be 100% compatible in this regard. The only difference is when your class has overridden private properties: `var_export()` will output an array that contains the same key twice (resulting in data loss), while `VarExporter` will throw an `ExportException` to keep you on the safe side.

    Unlike `var_export()`, this method will only be used if actually implemented on the class.

    You can disable exporting objects this way, even if they implement `__set_state()`, using the [`NO_SET_STATE`](#varexporterno_set_state) option.
- If your class has `__serialize()` and `__unserialize()` methods ([introduced in PHP 7.4](https://wiki.php.net/rfc/custom_object_serialization), but this library accepts them in previous versions of PHP!), `VarExporter` uses the output of `__serialize()` to export the object, and gives it as input to `__unserialize()` to reconstruct the object:

    ```
    (static function() {
        $class = new \ReflectionClass(\My\CustomClass::class);
        $object = $class->newInstanceWithoutConstructor();

        $object->__unserialize([
            'foo' => 'Test',
            'bar' => 1234
        ]);

        return $object;
    })()
    ```

    This method is recommended for exporting complex custom objects: it is forward compatible with the new serialization mechanism introduced in PHP 7.4, flexible, safe, and composes very well under inheritance.

    If for any reason you do not want to export objects that implement `__serialize()` and `__unserialize()` using this method, you can opt out by using the [`NO_SERIALIZE`](#varexporterno_serialize) option.
- If the class does not meet any of the conditions above, it is exported through direct property access, which in its simplest form looks like:

    ```
    (static function() {
        $object = new \My\CustomClass;

        $object->publicProp = 'Foo';
        $object->dynamicProp = 'Bar';

        return $object;
    })()
    ```

    If the class has a constructor, it will be bypassed using reflection:

    ```
    (static function() {
        $class = new \ReflectionClass(\My\CustomClass::class);
        $object = $class->newInstanceWithoutConstructor();

        ...
    })()
    ```

    If the class has non-public properties, they will be accessed through closures bound to the object:

    ```
    (static function() {
        $class = new \ReflectionClass(\My\CustomClass::class);
        $object = $class->newInstanceWithoutConstructor();

        $object->publicProp = 'Foo';
        $object->dynamicProp = 'Bar';

        (function() {
            $this->protectedProp = 'contents';
            $this->privateProp = 'contents';
        })->bindTo($object, \My\CustomClass::class)();

        (function() {
            $this->privatePropInParent = 'contents';
        })->bindTo($object, \My\ParentClass::class)();

        return $object;
    })()
    ```

    You can disable exporting objects this way, using the [`NOT_ANY_OBJECT`](#varexporternot_any_object) option.

If you attempt to export a custom object and all compatible exporters have been disabled, an `ExportException` will be thrown.

Exporting closures
------------------

[](#exporting-closures)

Since version `0.2.0`, `VarExporter` has experimental support for closures:

```
echo VarExporter::export([
    'callback' => function() {
        return 'Hello, world!';
    }
]);
```

```
[
    'callback' => function () {
        return 'Hello, world!';
    }
]
```

To do this magic, `VarExporter` parses the PHP source file where your closure is defined, using the well-established [nikic/php-parser](https://github.com/nikic/PHP-Parser) library, inspired by [SuperClosure](https://github.com/jeremeamia/super_closure).

To ensure that the closure will work in any context, it rewrites its source code, replacing any namespaced class/function/constant name with its fully qualified counterpart:

```
namespace My\App;

use My\App\Model\Entity;
use function My\App\Functions\imported_function;
use const My\App\Constants\IMPORTED_CONSTANT;

use Brick\VarExporter\VarExporter;

echo VarExporter::export(function(Service $service) : Entity {
    strlen(NON_NAMESPACED_CONSTANT);
    imported_function(IMPORTED_CONSTANT);
    \My\App\Functions\explicitly_namespaced_function(\My\App\Constants\EXPLICITLY_NAMESPACED_CONSTANT);

    return new Entity();
});
```

```
function (\My\App\Service $service) : \My\App\Model\Entity {
    strlen(NON_NAMESPACED_CONSTANT);
    \My\App\Functions\imported_function(\My\App\Constants\IMPORTED_CONSTANT);
    \My\App\Functions\explicitly_namespaced_function(\My\App\Constants\EXPLICITLY_NAMESPACED_CONSTANT);
    return new \My\App\Model\Entity();
}
```

Note how all namespaced classes, and explicitly namespaced functions and constants, have been rewritten, while the non-namespaced function `strlen()` and the non-namespaced constant have been left as is. This brings us to the first caveat:

### Caveats

[](#caveats)

- **Functions and constants that are not not explicitly namespaced**, either directly or through a `use function` or `use const` statement, **are always exported as is**. This is because the parser does not have the runtime context to check if a definition for this function or constant exists in the current namespace, and as such cannot reliably predict the behaviour of PHP's [fallback to global function/constant](https://www.php.net/manual/en/language.namespaces.fallback.php). Be really careful here if you're using namespaced functions or constants: **always explicitly import your namespaced functions and constants**, if any.
- **Closures that have variables bound through `use()` cannot be exported**, and will throw an `ExportException`. This is intentional, because exported closures can be executed in another context, and as such must not rely on the context they've been originally defined in.
- Closures can use `$this`, but **will not be bound to an object once exported**. You must explicitly bind them through [`bindTo()`](https://www.php.net/manual/en/closure.bindto.php) if required, after running the exported code.
- **You cannot have 2 closures on the same line in your source file**, or an `ExportException` will be thrown. This is because `VarExporter` cannot know which one holds the definition for the `\Closure` object it encountered.
- **Closures defined in eval()'d code cannot be exported** and throw an `ExportException`, because there is no source file to parse.

You can disable exporting closures, using the [`NO_CLOSURES`](#varexporterno_closures) option. When this option is set, an `ExportException` will be thrown when attempting to export a closure.

Options
-------

[](#options)

`VarExporter::export()` accepts a bitmask of options as a second parameter:

```
VarExporter::export($var, VarExporter::ADD_RETURN | VarExporter::ADD_TYPE_HINTS);
```

Available options:

### `VarExporter::ADD_RETURN`

[](#varexporteradd_return)

Wraps the output in a return statement:

```
return (...);
```

This makes the code ready to be executed in a PHP file―or `eval()`, for that matter.

### `VarExporter::ADD_TYPE_HINTS`

[](#varexporteradd_type_hints)

Adds type hints to objects created through reflection, and to `$this` inside closures bound to an object. This allows the resulting code to be statically analyzed by external tools and IDEs:

```
/** @var \My\CustomClass $object */
$object = $class->newInstanceWithoutConstructor();

(function() {
    /** @var \My\CustomClass $this */
    $this->privateProp = ...;
})->bindTo($object, \My\CustomClass::class)();
```

### `VarExporter::SKIP_DYNAMIC_PROPERTIES`

[](#varexporterskip_dynamic_properties)

Skips dynamic properties on custom classes in the output. Dynamic properties are properties that are not part of the class definition, and added to an object at runtime. By default, any dynamic property set on a custom class is exported; if this option is used, dynamic properties are only allowed on `stdClass` objects, and ignored on other objects.

### `VarExporter::NO_SET_STATE`

[](#varexporterno_set_state)

Disallows exporting objects through `__set_state()`.

### `VarExporter::NO_SERIALIZE`

[](#varexporterno_serialize)

Disallows exporting objects through `__serialize()` and `__unserialize()`.

### `VarExporter::NOT_ANY_OBJECT`

[](#varexporternot_any_object)

Disallows exporting any custom object using direct property access and bound closures.

### `VarExporter::NO_CLOSURES`

[](#varexporterno_closures)

Disallows exporting closures.

### `VarExporter::INLINE_NUMERIC_SCALAR_ARRAY`

[](#varexporterinline_numeric_scalar_array)

Formats numeric arrays containing only scalar values on a single line:

```
VarExporter::export([
    'one' => ['hello', 'world', 123, true, false, null, 7.5],
    'two' => ['hello', 'world', ['one', 'two', 'three']]
], VarExporter::INLINE_NUMERIC_SCALAR_ARRAY);
```

```
[
    'one' => ['hello', 'world', 123, true, false, null, 7.5],
    'two' => [
        'hello',
        'world',
        ['one', 'two', 'three']
    ]
]
```

Types considered scalar here are `int`, `bool`, `float`, `string` and `null`.

Error handling
--------------

[](#error-handling)

Any error occurring on `export()` will throw an `ExportException`:

```
use Brick\VarExporter\VarExporter;
use Brick\VarExporter\ExportException;

try {
    VarExporter::export(fopen('php://memory', 'r'));
} catch (ExportException $e) {
    // Type "resource" is not supported.
}
```

Limitations
-----------

[](#limitations)

- Exporting internal classes other than `stdClass` and `Closure` is currently not supported. `VarExporter` will throw an `ExportException` if it finds one.

    To avoid hitting this brick wall, you can implement `__serialize()` and `__unserialize()` in classes that contain references to internal objects.

    Feel free to open an issue or a pull request if you think that an internal class could/should be exportable.
- Exporting anonymous classes is not supported yet. Ideas or pull requests welcome.
- Just like `var_export()`, `VarExporter` cannot currently maintain object identity (two instances of the same object, once exported, will create two equal (`==`) yet distinct (`!==`) objects).
- And just like `var_export()`, it cannot currently handle circular references, such as object `A` pointing to `B`, and `B` pointing back to `A`.

In pretty much every other case, it offers an elegant and very efficient way to cache data to PHP files, and a solid alternative to serialization.

###  Health Score

23

—

LowBetter than 27% of packages

Maintenance26

Infrequent updates — may be unmaintained

Popularity6

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 99.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~96 days

Total

2

Last Release

2352d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7a6bd4b7a52a1ed056c6d597c4124a62da080137edd42cc34355ac2c28e4a154?d=identicon)[francislavoie](/maintainers/francislavoie)

---

Top Contributors

[![BenMorel](https://avatars.githubusercontent.com/u/1952838?v=4)](https://github.com/BenMorel "BenMorel (136 commits)")[![francislavoie](https://avatars.githubusercontent.com/u/2111701?v=4)](https://github.com/francislavoie "francislavoie (1 commits)")

---

Tags

var\_export

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/francislavoie-varexporter/health.svg)

```
[![Health](https://phpackages.com/badges/francislavoie-varexporter/health.svg)](https://phpackages.com/packages/francislavoie-varexporter)
```

###  Alternatives

[symfony/maker-bundle

Symfony Maker helps you create empty commands, controllers, form classes, tests and more so you can forget about writing boilerplate code.

3.4k111.1M568](/packages/symfony-maker-bundle)[brick/varexporter

A powerful alternative to var\_export(), which can export closures and objects without \_\_set\_state()

19429.7M72](/packages/brick-varexporter)[roave/backward-compatibility-check

Tool to compare two revisions of a public API to check for BC breaks

5953.3M56](/packages/roave-backward-compatibility-check)[coenjacobs/mozart

Composes all dependencies as a package inside a WordPress plugin

4723.6M20](/packages/coenjacobs-mozart)[psalm/plugin-laravel

Psalm plugin for Laravel

3274.9M308](/packages/psalm-plugin-laravel)[recca0120/laravel-erd

Laravel ERD automatically generates Entity-Relationship Diagrams from your Laravel models and displays them using Vuerd.

36072.0k](/packages/recca0120-laravel-erd)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
