定制 hershel-theodore-layton/expr-dump 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

hershel-theodore-layton/expr-dump

Composer 安装命令:

composer require hershel-theodore-layton/expr-dump

包简介

Dump runtime values to typed Hack source code.

README 文档

README

Dump runtime values to typed Hack source code.

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 snippet1 embodies the essence of this library perfectly.

function burn_a_value_to_constant<reify T>(
  string $constant_name,
  T $value,
  ExprDump\DumpOptions $dumper_options = shape(),
)[]: string {
  $type_name = TypeVisitor\visit<T, _, _>(new TypeVisitor\TypenameVisitor());
  $serialized_value = ExprDump\dump<T>($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

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<reify T>(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

// Like var_dump(), with Hack syntax, all type information is lost.
//  - shapes become dicts
//  - tuples become vecs
//  - enums become ints / strings
ExprDump\dump<mixed>($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<vec<shape('name' => string, 'friends' => vec<App\UserId>)>>(
  $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<vec<Roles>>(
  $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<shape(SomeClass::CONSTANT => int)>(
  $shape,
  shape(
    'shape_key_namer' => (
      ?string $_parent_shape_name,
      arraykey $key,
    )[] ==> {
      $prefix = '\\'.SomeClass::class.'::';
      return dict<arraykey, string>[
        SomeClass::CONSTANT => $prefix.'CONSTANT',
      ][$key] ?? null;
    },
  ),
);

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

$dumper->dump($value_of_that_given_type);

Note about the stability of this api

This library depends on HTL\TypeVisitor to provide its functionality. TypeVisitor depends on unstable Hack apis, TypeStructure<T> and \HH\ReifiedGenerics\get_type_structure<T>(). For more details, see stability. 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.

hershel-theodore-layton/expr-dump 适用场景与选型建议

hershel-theodore-layton/expr-dump 是一款 基于 Hack 开发的 Composer 扩展包,目前已累计 367 次下载、GitHub Stars 达 1, 最近一次更新时间为 2024 年 02 月 13 日, 在 PHP 生态内属于活跃度较高的组件。

我们在过去多个企业项目中使用过 hershel-theodore-layton/expr-dump 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 hershel-theodore-layton/expr-dump 我们能提供哪些服务?
定制开发 / 二次开发

基于 hershel-theodore-layton/expr-dump 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 367
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 1
  • 点击次数: 18
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 1
  • Watchers: 1
  • Forks: 0
  • 开发语言: Hack

其他信息

  • 授权协议: MIT
  • 更新时间: 2024-02-13