Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Var Exporter Laravel Package

symfony/var-exporter

Symfony VarExporter lets you export any serializable PHP value to fast, OPcache-friendly PHP code (preserving __sleep/__wakeup, Serializable, __serialize). Includes Instantiator/Hydrator for bypassing constructors, deep cloning, and lazy-loading traits.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require symfony/var-exporter
    

    No additional configuration is needed—just autoload the package.

  2. First Use Case: Export a complex object to PHP code for debugging, caching, or testing:

    use Symfony\Component\VarExporter\VarExporter;
    
    $user = new User(['name' => 'John', 'roles' => ['admin']]);
    $exportedCode = VarExporter::export($user);
    // Outputs: `return new User(['name' => 'John', 'roles' => ['admin']]);`
    
  3. Where to Look First:

    • Official Documentation
    • VarExporter::export() for serialization.
    • Instantiator/Hydrator for object manipulation.

Implementation Patterns

1. Exporting Objects for Debugging/Caching

  • Pattern: Replace var_dump() or serialize() for human-readable, reusable code.
// Debugging a complex query result
$results = $userRepository->findAll();
file_put_contents('debug/results.php', '<?php return ' . VarExporter::export($results) . ';');
  • Use Case: Generate test fixtures or cached responses.

2. Instantiating Objects Without Constructors

  • Pattern: Bypass constructors for testing or performance-critical paths.
use Symfony\Component\VarExporter\Instantiator;

$user = Instantiator::instantiate(User::class, ['name' => 'Alice']);
// Skips constructor logic (e.g., validation, side effects).

3. Hydrating Objects (Including Private Properties)

  • Pattern: Set properties dynamically, even private ones.
use Symfony\Component\VarExporter\Hydrator;

$user = new User();
Hydrator::hydrate($user, ['name' => 'Bob']);
// For private properties (e.g., from a parent class):
Hydrator::hydrate($user, [], [
    User::class => ['privateToken' => 'secret123'],
]);

4. Deep Cloning for Performance

  • Pattern: Replace unserialize(serialize($obj)) with memory-efficient cloning.
use Symfony\Component\VarExporter\DeepCloner;

$cloner = new DeepCloner($originalObject);
$clone1 = $cloner->clone(); // Faster than serialize/unserialize.

5. Lazy-Loading Objects

  • Pattern: Defer expensive initialization (e.g., database queries).
use Symfony\Component\VarExporter\Proxy\ProxyHelper;

$proxyCode = ProxyHelper::generateLazyProxy(new ReflectionClass(User::class));
eval('class UserLazyProxy ' . $proxyCode);

$user = UserLazyProxy::createLazyProxy(function () {
    return new User(['name' => 'Lazy User']);
});
// $user->getName() triggers the initializer.

6. Integration with Laravel

  • Testing: Export Eloquent models for test data.
    $user = User::find(1);
    $fixture = VarExporter::export($user);
    
  • Caching: Store exported objects in Redis/Memcached.
    $cached = cache()->get('user_1');
    if (!$cached) {
        $user = User::find(1);
        $cached = VarExporter::export($user);
        cache()->put('user_1', $cached, now()->addHour());
    }
    eval('return ' . $cached); // Reconstruct object.
    

Gotchas and Tips

Pitfalls

  1. Class Not Found Exceptions:

    • If a class is missing during export, ClassNotFoundException is thrown (unlike serialize()).
    • Fix: Ensure all referenced classes are autoloadable or mock them in tests.
  2. Readonly Properties:

    • Hydration skips initialized readonly properties (PHP 8.2+).
    • Workaround: Use Instantiator to set readonly properties during instantiation.
  3. Circular References:

    • VarExporter handles them, but deep cloning may still fail for complex graphs.
    • Tip: Use DeepCloner for large objects to avoid memory issues.
  4. Lazy Proxies and eval:

    • Generated proxy classes require eval(). In production, pre-generate and cache them.
    • Security: Only use with trusted code (e.g., internal classes).
  5. PHP 8.4+ Lazy Objects:

    • Native lazy objects replace LazyGhostTrait/LazyProxyTrait. Update old code to use ProxyHelper.

Debugging Tips

  • Inspect Exported Code:
    $exported = VarExporter::export($obj, VarExporter::EXPORT_DEBUG);
    // Adds comments like `// class User { ... }`.
    
  • Validate Hydration: Use ReflectionProperty to verify property values after hydration:
    $reflection = new ReflectionProperty(User::class, 'privateField');
    $reflection->setAccessible(true);
    $value = $reflection->getValue($user);
    

Performance Quirks

  • OPcache Benefits: Exported code runs faster than unserialize() due to OPcache optimization. Tip: Cache exported code in production (e.g., file_put_contents()).

  • DeepCloner vs. serialize(): DeepCloner is ~3x faster for large objects but requires PHP 7.4+. Benchmark:

    $start = microtime(true);
    $clone = DeepCloner::deepClone($bigObject);
    echo microtime(true) - $start; // Compare with serialize/unserialize.
    

Extension Points

  1. Custom Exporters: Extend VarExporter for domain-specific serialization:

    class CustomExporter extends VarExporter {
        public static function export($value, array $options = []) {
            $options[VarExporter::EXPORT_DEBUG] = true;
            return parent::export($value, $options);
        }
    }
    
  2. Hydrator Callbacks: Use closures to transform values during hydration:

    Hydrator::hydrate($user, [
        'name' => fn($val) => strtoupper($val),
    ]);
    
  3. Lazy Proxy Initializers: Add logic to initialize proxies dynamically:

    $proxy = UserLazyProxy::createLazyProxy(function () {
        return User::query()->findOrFail(1);
    });
    

Laravel-Specific Gotchas

  • Eloquent Models: Avoid exporting models with unserializable relationships (e.g., belongsToMany with custom accessors). Fix: Use ->toArray() or ->fresh() before exporting.

  • Service Container: Instantiator bypasses container bindings. Use app()->make() for dependency injection:

    $user = Instantiator::instantiate(User::class);
    $user->setRepository(app()->make(UserRepository::class));
    
  • Testing: Export fixtures to database/fixtures/ and load them in DatabaseSeeder:

    $fixture = file_get_contents('fixtures/user.php');
    eval('User::insert(' . $fixture . ');');
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport