componenta/var-export 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

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

componenta/var-export

Composer 安装命令:

composer require componenta/var-export

包简介

Export PHP variables to their string representation with support for closures, arrays, and configurable formatting

README 文档

README

PHP Version License Tests

Round-trip PHP values to executable source code. Unlike var_export(), this library handles closures, readonly value objects and enums — and keeps namespace semantics intact so the exported code evaluates correctly anywhere.

Русская версия

Features

  • Closures — full AST-based export with correct name resolution (class refs → FQN, function/constant refs keep global fallback)
  • Readonly value objects — round-tripped via new ClassName(...) when every constructor parameter is a public property
  • Enums — both pure and backed cases
  • Arrays — sequential, associative, mixed, unlimited nesting (guarded by maxDepth)
  • Configurable output — pretty or compact layout, custom indent, sorted keys, trailing commas
  • Typed exceptions — precise error context without leaking the values that caused them

Requirements

  • PHP 8.4+
  • nikic/php-parser ^5.0

Related Packages

Package Why it matters here
componenta/config Uses export for executable PHP configuration cache files.
componenta/app Application cache can persist compiled arrays and descriptors as PHP files.
componenta/di Compiled DI plans and dependency cache should be executable PHP arrays.
nikic/php-parser Required for closure export and name-resolution semantics.

Installation

composer require componenta/var-export

Quick start

use Componenta\VarExport\Export;

// Any value — returns executable PHP code
Export::var(['host' => 'localhost', 'port' => 5432]);
// → ['host' => 'localhost', 'port' => 5432]

// Pretty layout (multi-line + trailing comma)
Export::pretty([1, 2, 3]);
// → [
//       1,
//       2,
//       3,
//   ]

// Closures — namespace-aware
$handler = static fn(int $x): int => $x * 2;
Export::closure($handler);
// → static fn(int $x): int => $x * 2

// For file output — appends the semicolon
Export::toFile(['env' => 'prod']);
// → ['env' => 'prod'];

Round-trip works through eval() (and any PHP source file):

$code = Export::var($original);
$restored = eval("return {$code};");
// $restored === $original

Configuration

use Componenta\VarExport\Config\ExportConfig;
use Componenta\VarExport\Config\ClosureUseMode;
use Componenta\VarExport\Config\FormatterMode;

$config = new ExportConfig(
    mode:           FormatterMode::Pretty,
    indent:         '    ',                 // spaces or tabs
    maxDepth:       64,                     // guards runaway recursion
    sortKeys:       false,                  // sort associative array keys
    trailingComma:  true,                   // add trailing comma in pretty mode
    closureUseMode: ClosureUseMode::Preserve,
);

// Presets
ExportConfig::pretty();   // multi-line + trailing comma
ExportConfig::compact();  // single-line

// Fluent copies (every with* returns a new instance)
$config = ExportConfig::pretty()
    ->withIndent("\t")
    ->withSortKeys();

Reusing an exporter

One-off calls go through the static facade. For many exports with the same configuration, instantiate VarExporter directly — the parsed-AST cache is reused across calls:

use Componenta\VarExport\VarExporter;

$exporter = new VarExporter(ExportConfig::pretty());
$a = $exporter->export($closure1);
$b = $exporter->export($closure2);  // closure1's file AST is cached

Closure capture modes

ClosureUseMode::Preserve (default)

Keeps the use(...) clause verbatim. The captured variables must exist in the scope where the exported code runs.

$multiplier = 2;
$fn = function (int $x) use ($multiplier): int {
    return $x * $multiplier;
};

Export::closure($fn);
// → function (int $x) use ($multiplier): int { return $x * $multiplier; }

ClosureUseMode::Inline

Replaces each use(...) variable with its current value, yielding a self-contained closure:

$config = new ExportConfig(closureUseMode: ClosureUseMode::Inline);

Export::closure($fn, $config);
// → function (int $x): int { return $x * 2; }

Inline mode accepts scalar captures and nested scalar arrays. Captures of objects, resources, nested closures or by-reference variables (use (&$x)) are rejected with ClosureExportException.

Exporting objects

enum Priority: string {
    case Low = 'low';
    case High = 'high';
}

final readonly class Task {
    public function __construct(
        public string $title,
        public Priority $priority,
        public array $tags,
    ) {}
}

Export::var(new Task('Ship', Priority::High, ['core']));
// → new \App\Task('Ship', \App\Priority::High, ['core'])

Requirements for readonly-class export:

  • Class is marked readonly
  • Every constructor parameter has a matching public property

ObjectExporter::supports($object) reports up front whether a given object satisfies these rules — use it to pre-flight untrusted input.

Helper functions

For callers that prefer free functions over static methods:

use function Componenta\VarExport\var_export_string;
use function Componenta\VarExport\var_export_pretty;
use function Componenta\VarExport\array_export;
use function Componenta\VarExport\closure_export;

var_export_string($value);
var_export_string($value, pretty: true);
var_export_pretty($value);
array_export([1, 2, 3]);
closure_export(fn() => 42);

Error handling

use Componenta\VarExport\Exception\{
    ExportException,
    ArrayExportException,
    ClosureExportException,
    ConfigurationException,
};

try {
    $code = Export::var($data);
} catch (ArrayExportException $e) {
    // Max depth, unexportable element, key path context in $e->context
} catch (ClosureExportException $e) {
    // Bound $this, inline captures not supported, ambiguous location
} catch (ConfigurationException $e) {
    // Invalid indent / maxDepth in ExportConfig
} catch (ExportException $e) {
    // Unsupported top-level type
}

Every exception carries a $context array with metadata (class, key path, variable names, file/line) — values that caused the failure are not stored, so logs stay safe.

Not supported

  • Mutable objects (non-readonly, or with private state that cannot be reconstructed through the constructor)
  • Resources (including stream/curl handles)
  • Closures bound to $this — convert to static function() { ... } before export
  • Closures defined in eval()'d code (no source file to parse)
  • Two or more closures on the same line with identical signatures (ambiguous — keep them on separate lines)

License

MIT

统计信息

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

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-06-14

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固