PHPackages                             hershel-theodore-layton/expr-dump - 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. hershel-theodore-layton/expr-dump

ActiveLibrary

hershel-theodore-layton/expr-dump
=================================

Dump runtime values to typed Hack source code.

v1.2.1(6mo ago)1277MITHackCI passing

Since Feb 15Pushed 2mo ago1 watchersCompare

[ Source](https://github.com/hershel-theodore-layton/expr-dump)[ Packagist](https://packagist.org/packages/hershel-theodore-layton/expr-dump)[ RSS](/packages/hershel-theodore-layton-expr-dump/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (8)Dependencies (5)Versions (9)Used By (0)

expr-dump
=========

[](#expr-dump)

Dump runtime values to typed Hack source code.

Why do you need this?
---------------------

[](#why-do-you-need-this)

Run code during build-time, codegen the values you were interested in back to Hack code, write it to a Hack source file, and you have build-time compute.

The following snippet[1](#user-content-fn-1-98b6a10631ffd84c2c1bbe8eccf52b6b) embodies the essence of this library perfectly.

```
function burn_a_value_to_constant(
  string $constant_name,
  T $value,
  ExprDump\DumpOptions $dumper_options = shape(),
)[]: string {
  $type_name = TypeVisitor\visit(new TypeVisitor\TypenameVisitor());
  $serialized_value = ExprDump\dump($value, $dumper_options);
  return Str\format(
    'const %s %s = %s;',
    $type_name,
    $constant_name,
    $serialized_value,
  );
}
```

All data that enters your program at runtime is typed as `mixed`, which is why you must cast it to a typed value in order to process it. If you do this safely, this incurs runtime costs. Doing it using an unsafe mechanism, such as `HH\FIXME\UNSAFE_CAST` or `HH_FIXME[4110]` is trading correctness for performance. But with `burn_a_value_to_constant`, the data doesn't enter the program at runtime. This data is already typed, so there is no need for casting.

Why the existing tools can not meet this need
---------------------------------------------

[](#why-the-existing-tools-can-not-meet-this-need)

In Hack, the same runtime value can represent two different types.

```
shape('name' => 'value') === dict['name' => 'value']; // true
shape('name' => 'value') === shape(SomeClass::CLASS_CONSTANT => 'value'); // true
vec[1, 2, 3] === tuple(1, 2, 3); // true
6 === MyEnum::ENUMERATOR; // true
```

HHVM is unable to distinguish between these types, but Hack is, and will emit errors if you initialize a value with the wrong type, even if the runtime value would be exactly the same as the correct initializer.

`const (int, int) A_TUPLE = vec[1, 2]; // type error`

`ExprDump\dump(T $value): string` takes a **type** *and a* value. This gives it enough information to represent shapes as shapes, tuples as tuples, enums as enums, whilst not confusing them for dicts, vecs, and arraykeys.

Usage
-----

[](#usage)

```
// Like var_dump(), with Hack syntax, all type information is lost.
//  - shapes become dicts
//  - tuples become vecs
//  - enums become ints / strings
ExprDump\dump($x);

// There are multiple options that can be combined in any way.

// Encode Hack types and aliasses how you please.
// \App\user_id_from_int(4) types the value as an App\UserId.
ExprDump\dump string, 'friends' => vec)>>(
  $users,
  shape(
    'custom_dumpers' => dict[
      App\UserId::class => (mixed $id)[] ==>
        '\App\user_id_from_int('.($id as int).')',
    ],
  ),
);

// Serialize enums as enumeration expression, such as Roles::ADMIN.
ExprDump\dump(
  $roles,
  shape(
    'enum_definitions' => ExprDump\EnumDefinition::create(Roles::class),
  ),
);

// Keep class constant names in the dumped output.
// shape(\SomeClass::CONSTANT => 1) instead of shape('val' => 1)
ExprDump\dump int)>(
  $shape,
  shape(
    'shape_key_namer' => (
      ?string $_parent_shape_name,
      arraykey $key,
    )[] ==> {
      $prefix = '\\'.SomeClass::class.'::';
      return dict[
        SomeClass::CONSTANT => $prefix.'CONSTANT',
      ][$key] ?? null;
    },
  ),
);

// Create a reusable dumper, call `->dump()`
$dumper = ExprDump\create_dumper(shape(
  // The options go here
));

$dumper->dump($value_of_that_given_type);
```

Note about the stability of this api
------------------------------------

[](#note-about-the-stability-of-this-api)

This library depends on [HTL\\TypeVisitor](https://github.com/herhsel-theodore-layton/type-visitor)to provide its functionality. `TypeVisitor` depends on unstable Hack apis, `TypeStructure` and `\HH\ReifiedGenerics\get_type_structure()`. For more details, see [stability](https://github.com/hershel-theodore-layton/type-visitor/blob/master/README.md). This api has been unstable since 2016, so take this with a grain of salt.

In order to minimize the potential impact of a removal of these apis, you should not use this library in places where the performance of bootstrapping the dumper is critical. A far less performant variant of `TypeVisitor` could be written, even without these api affordances.

Footnotes
---------

1. This snippet `burn_a_value_to_constant` is excempt from the MIT license of this library. It is licensed to you under MIT-0 (MIT No Attribution). This excemption does not apply to the code called by this snippet. The MIT license still covers all other parts of this program. [↩](#user-content-fnref-1-98b6a10631ffd84c2c1bbe8eccf52b6b)

###  Health Score

39

—

LowBetter than 86% of packages

Maintenance76

Regular maintenance activity

Popularity16

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~89 days

Recently: every ~40 days

Total

8

Last Release

197d ago

Major Versions

v0.2.1 → v1.0.02024-12-07

### Community

Maintainers

![](https://www.gravatar.com/avatar/d16d159b7061287c506d4ab44d05ae042bc4ec697116d1bd132a007634d9ff21?d=identicon)[Hershel Theodore Layton](/maintainers/Hershel%20Theodore%20Layton)

---

Top Contributors

[![hershel-theodore-layton](https://avatars.githubusercontent.com/u/81193606?v=4)](https://github.com/hershel-theodore-layton "hershel-theodore-layton (53 commits)")

### Embed Badge

![Health badge](/badges/hershel-theodore-layton-expr-dump/health.svg)

```
[![Health](https://phpackages.com/badges/hershel-theodore-layton-expr-dump/health.svg)](https://phpackages.com/packages/hershel-theodore-layton-expr-dump)
```

###  Alternatives

[hhvm/hsl

The Hack Standard Library

1151.1M55](/packages/hhvm-hsl)

PHPackages © 2026

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