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

Exports serializable PHP values to fast, OPcache-friendly PHP code, preserving serialization semantics and references. Includes DeepCloner for efficient deep cloning and ProxyHelper to generate lazy-loading proxies; uses ext-deepclone (or polyfill) for speed.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require symfony/var-exporter
    

    Ensure ext-deepclone is installed for optimal performance, or use the polyfill.

  2. First Use Case: Export a complex object to reusable PHP code:

    use Symfony\Component\VarExporter\VarExporter;
    
    $user = new User('John', ['role' => 'admin']);
    $exported = VarExporter::export($user);
    // Output: `new User('John', ['role' => 'admin'])`
    
  3. Where to Look First:

    • Official Documentation
    • VarExporter::export() for serialization.
    • DeepCloner for cloning objects efficiently.
    • ProxyHelper for lazy-loading abstract/internal classes.

Implementation Patterns

1. Exporting Objects for Debugging/Logging

  • Pattern: Export objects to structured PHP code for logs or cache.
$exported = VarExporter::export($entity, VarExporter::EXPORT_DEBUG);
Log::debug('Entity state:', ['data' => $exported]);
  • Use Case: Debugging complex domain models (e.g., Doctrine entities) without exposing sensitive data.

2. Efficient Cloning with DeepCloner

  • Pattern: Clone objects with copy-on-write semantics for performance.
$cloner = new DeepCloner($prototype);
$clone1 = $cloner->clone(); // Reuses memory for strings/arrays
$clone2 = $cloner->clone();
  • Use Case: Repeated cloning in tests or caching layers (e.g., cloning Request objects).

3. Lazy-Loading Abstract/Internal Classes

  • Pattern: Generate lazy proxies for expensive-to-instantiate objects.
$proxyCode = ProxyHelper::generateLazyProxy(new ReflectionClass(AbstractService::class));
eval('class AbstractServiceLazyProxy'.$proxyCode);

$service = AbstractServiceLazyProxy::createLazyProxy(
    initializer: fn() => new ConcreteService(/* ... */)
);
  • Use Case: Deferring initialization of heavy services (e.g., DatabaseConnection) until first use.

4. Integration with Laravel

  • Service Container: Bind VarExporter and DeepCloner as singletons:
    $this->app->singleton(DeepCloner::class, fn() => new DeepCloner());
    
  • Event Listeners: Export objects in illuminate\queue\FailedJob events for debugging:
    use Symfony\Component\VarExporter\VarExporter;
    
    public function handle(FailedJob $event)
    {
        $exported = VarExporter::export($event->job->payload());
        Log::error('Failed job:', ['payload' => $exported]);
    }
    

5. Caching Exported Data

  • Pattern: Cache exported PHP code for reuse (e.g., configuration objects).
$cacheKey = 'config_export_' . md5(serialize($config));
$exported = Cache::remember($cacheKey, 3600, fn() => VarExporter::export($config));
eval($exported); // Rehydrate when needed

Gotchas and Tips

Pitfalls

  1. Class Not Found Exceptions:

    • Exporting objects with missing classes throws ClassNotFoundException. Use VarExporter::EXPORT_NOT_SERIALIZABLE to skip them:
      VarExporter::export($obj, VarExporter::EXPORT_NOT_SERIALIZABLE);
      
  2. Readonly Properties:

    • Hydration may fail on readonly properties. Use VarExporter::EXPORT_HYDRATE_READONLY to force hydration:
      VarExporter::export($obj, VarExporter::EXPORT_HYDRATE_READONLY);
      
  3. Circular References:

    • DeepCloner handles circular references, but deep exports may hit recursion limits. Use VarExporter::EXPORT_CYCLIC:
      VarExporter::export($obj, VarExporter::EXPORT_CYCLIC);
      
  4. Lazy Proxies and __unserialize:

    • Avoid calling __unserialize directly on lazy proxies. Use ProxyHelper::generateLazyProxy() with a custom initializer.
  5. Performance with ext-deepclone:

    • Without ext-deepclone, DeepCloner falls back to slower methods. Benchmark with:
      $time = microtime(true);
      $clone = DeepCloner::deepClone($obj);
      Log::debug('Cloning took:', [microtime(true) - $time]);
      

Debugging Tips

  1. Inspect Exported Code: Use VarExporter::export($obj, VarExporter::EXPORT_DEBUG) to see the generated PHP code.

  2. Validate Hydration: After exporting/hydrating, validate the object state:

    $hydrated = VarExporter::hydrate($exported);
    assert($hydrated instanceof User);
    assert($hydrated->name === 'John');
    
  3. Lazy Proxy Debugging: Override createLazyProxy to log initialization:

    $proxy = AbstractServiceLazyProxy::createLazyProxy(
        initializer: fn() => {
            Log::debug('Initializing AbstractService');
            return new ConcreteService();
        }
    );
    

Extension Points

  1. Custom Exporters: Extend VarExporter to handle custom types:

    class CustomExporter extends VarExporter
    {
        public static function export($value, int $flags = 0): string
        {
            if ($value instanceof CustomClass) {
                return 'new CustomClass(' . self::export($value->data) . ')';
            }
            return parent::export($value, $flags);
        }
    }
    
  2. DeepCloner Callbacks: Use DeepCloner::setCallback() to modify cloning behavior:

    $cloner = new DeepCloner();
    $cloner->setCallback(CustomClass::class, fn($obj) => clone $obj->withNewData());
    
  3. Proxy Customization: Modify ProxyHelper output by subclassing and overriding generateLazyProxy():

    class CustomProxyHelper extends ProxyHelper
    {
        protected function generateProxyClass(ReflectionClass $class): string
        {
            // Custom logic here
            return parent::generateProxyClass($class);
        }
    }
    

Laravel-Specific Quirks

  1. Blade Templates: Avoid exporting objects directly in Blade (use VarExporter in controllers instead):

    // Controller (safe)
    $exported = VarExporter::export($user);
    return view('user', ['exported' => $exported]);
    
    // Blade (unsafe: eval in templates is discouraged)
    @php eval($exported); @endphp
    
  2. Queue Jobs: Export job payloads for debugging failed jobs:

    public function handle(FailedJob $event)
    {
        $payload = VarExporter::export($event->job->payload(), VarExporter::EXPORT_DEBUG);
        Log::error('Failed job payload:', ['payload' => $payload]);
    }
    
  3. Eloquent Models: Use VarExporter to debug relationships:

    $user = User::with('posts')->find(1);
    $exported = VarExporter::export($user, VarExporter::EXPORT_DEBUG);
    Log::debug('User with posts:', ['data' => $exported]);
    
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.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai