Weave 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

Json Serializer Laravel Package

zumba/json-serializer

A PHP library that serializes variables and objects to JSON and restores them, including binary data, nested objects, recursion, and closures. Requires PHP 7.2+; never unserialize untrusted input.

View on GitHub
Deep Wiki
Context7

Getting Started

First Steps

  1. Installation

    composer require zumba/json-serializer:^3.2.5
    

    The package is auto-discoverable in Laravel 5.5+ (no manual provider registration needed).

    Upgrade note (3.2.5): If you pinned ^3.2.4 and run PHP 7.2 or 7.3, upgrade immediately — 3.2.4 shipped a ReflectionProperty::isInitialized() call that is a fatal error below PHP 7.4. On PHP 8.5, 3.2.4 also emits deprecations from SplObjectStorage::contains()/attach() and ReflectionProperty::setAccessible(). Both are resolved in 3.2.5, which is now CI-tested on PHP 7.2 through 8.5.

  2. Verify your runtime matrix

    php -v
    composer why-not zumba/json-serializer 3.2.5
    

    Check that your composer.json require.php constraint and your Docker/CI images actually line up with what the package supports. The 3.2.4 → 3.2.5 regression is exactly the class of bug that only shows up when your production PHP differs from your dev PHP.

  3. Basic Usage

    use Zumba\JsonSerializer\JsonSerializer;
    
    $serializer = app(JsonSerializer::class);
    $data = ['name' => 'John', 'age' => 30, 'active' => true];
    
    // Serialize
    $json = $serializer->serialize($data);
    // '{"name":"John","age":30,"active":true}'
    
    // Unserialize
    $decoded = $serializer->unserialize($json);
    // ['name' => 'John', 'age' => 30, 'active' => true]
    
  4. First Use Case

    • Object hydration round-trips: persisting DTOs, value objects, or job payloads into Redis/DB and getting the same object graph back, private properties included.
    • Caching: serialize complex objects (e.g. Eloquent models) to store in Redis/Memcached with a custom handler for dates.
    • Parent Class Properties: supports serialization of private properties from both parent and child classes (added in v3.2.4).
    • Typed Properties: uninitialized typed properties (e.g. public string $name) serialize to null instead of fataling — on PHP 7.4+ only, which 3.2.4 failed to check for.
    • Security: read SECURITY.md before you ever point unserialize() at request data.

Implementation Patterns

Common Workflows

  1. Object Serialization (Including Parent/Child Class Properties)

    class ParentClass {
        private $secret = 'hidden';
    }
    
    class ChildClass extends ParentClass {
        public $name = 'Alice';
        private $privateData = 'child_secret';
    }
    
    $child = new ChildClass();
    $json = $serializer->serialize($child);
    // Now includes private properties from parent AND child classes
    
  2. Typed Properties in DTOs and Events

    class User {
        public string $name;        // uninitialized → null in JSON
        public int $age;
        public ?DateTime $createdAt;
    }
    
    $json = $serializer->serialize(new User());
    // '{"name":null,"age":null,"createdAt":null}'
    

    This is the pattern that broke on PHP 7.2/7.3 in 3.2.4 and is fixed in 3.2.5. If any of your services still run 7.2/7.3, treat 3.2.4 as a broken release, not just an older one.

  3. Queue Job Payloads

    class RebuildReport implements ShouldQueue
    {
        use SerializesModels;
    
        public function __construct(public ReportDefinition $definition) {}
    
        public function handle(JsonSerializer $serializer): void
        {
            $cached = $serializer->serialize($this->definition);
            Cache::put("report_def:{$this->definition->id}", $cached, now()->addDay());
        }
    }
    

    Serializing once at dispatch/queue time is far cheaper than re-serializing on every read.

  4. Custom Handlers for Special Types

    $serializer->setDateTimeHandler(fn ($date) => $date->format('Y-m-d H:i:s'));
    
    $serializer->setObjectHandler('Carbon\Carbon', fn ($carbon) => $carbon->toIso8601String());
    
    $serializer->setCircularReferenceHandler(
        fn ($object, $path) => "[Circular Reference: {$path}]"
    );
    

    Register handlers in a service provider binding so every consumer gets identical formatting — date format drift between services is the most common source of "it deserialized but the data is wrong".

  5. Integration with Laravel

    • API Resources — keep serialization at the boundary, not in the resource:
      public function toArray($request)
      {
          return $this->serializer->serialize($this->resource->toArray(), [
              'exclude' => ['password', 'api_token'],
          ]);
      }
      
    • Middleware for Input Sanitization — validate first, then decode:
      public function handle($request, Closure $next)
      {
          $validator = Validator::make($request->all(), ['data' => ['required', 'json']]);
          $validator->validate();
      
          $request->merge($this->serializer->unserialize($request->input('data')));
      
          return $next($request);
      }
      
    • Eloquent model casts stay on the framework side; use the serializer only where you need round-trip object graph fidelity (relationships, private state).
  6. Batch Processing

    $jsonArray = User::query()
        ->cursor()
        ->map(fn ($user) => $serializer->serialize($user))
        ->all();
    

    cursor() over all() keeps memory flat; the serializer itself has no streaming mode, so chunking is your responsibility.

  7. Closures (opis/closure v4)

    $serializer->setObjectHandler('Closure', fn ($closure) => 'Closure detected');
    

Gotchas and Tips

Pitfalls

  1. PHP version drift between 3.2.4 and 3.2.5 The 3.2.5 changelog is essentially "3.2.4 was only safe on PHP 7.4–8.4". If you deploy a single lockfile across a mixed fleet (e.g. an old queue worker container on PHP 7.3 alongside PHP 8.3 web nodes), standardize on 3.2.5 everywhere before merging the upgrade PR.

  2. PHP 8.5 deprecation noise 3.2.5 silences SplObjectStorage::contains()/attach() and ReflectionProperty::setAccessible() deprecations. If your error tracker pages on deprecations, upgrade before turning on 8.5 in staging — otherwise you will get alerts that look like new bugs.

  3. Circular references Default behavior returns a placeholder ([Circular Reference: path]) rather than throwing. Customize via setCircularReferenceHandler — and log the path in non-production so you can find the offending relation.

  4. Private/protected properties Serialized by default, including inherited ones. Never assume "private" means "not in the payload" when handing a JSON string to a client or a log sink:

    $json = $serializer->serialize($object, ['exclude' => ['secret', 'password']]);
    

    Build an allowlist-based exclude in a base DTO rather than relying on per-call discipline.

  5. Uninitialized typed properties Now null instead of a fatal error. If null in a non-nullable property is worse for you than an exception, enforce it at your own boundary (validation rule or a strict mode flag if your version exposes one) rather than trusting the serializer to catch it.

  6. Performance with large data

    $cached = cache()->remember("user_{$user->id}_serialized", now()->addHour(), function () use ($user, $serializer) {
        return $serializer->serialize($user);
    });
    

    Never serialize inside a Blade loop or an N+1 accessor — it re-reflects the whole object graph each call.

  7. Security unserialize() on request input is a deserialization gadget surface. Treat it like eval(): only decode payloads your own application produced, and prefer HMAC-signed payloads or a whitelist of allowed classes if the API supports one.

  8. CI coverage, not feature coverage The 3.2.5 headline is that CI now runs on every supported PHP version, 7.2 → 8.5. That is a real improvement, but it also means 3.2.4's bugs were matrix bugs. Mirror the same matrix in your own pipeline (or at least in your dependency-bump job) so the next reflection-based change gets caught by your CI instead of your users.

Debugging Tips

  • Reproduce against the exact PHP minor version — docker run --rm -v $(pwd):/app -w /app php:7.3-cli composer test. A ReflectionProperty fatal in 3.2.4 looks nothing like the deprecation in 8.5.
  • Validate JSON output:
    $json = $serializer->serialize($data);
    if (json_validate($json)) { /* safe to store/return */ }
    
  • Log circular reference paths:
    $serializer->setCircularReferenceHandler(function ($object, $path) {
        Log::debug("Circular reference detected at: {$path}");
        return '[Circular]';
    });
    
  • Diff the round-trip, not the string — assertEquals($original, $serializer->unserialize($serializer->serialize($original))) catches private-state and type loss that eyeballing JSON never will.
  • Check the changelog before bumping — with a package this reflection-heavy, read the release notes for the PHP version matrix line first; it is the single most load-bearing sentence in each release.

Extension Points

  1. Custom serializers Implement the package's serializer contract for domain-specific logic (money, enums, IDs) and bind it in a service provider so the rest of the app never calls serialize() directly.

  2. Object handlers setObjectHandler() per class is the cheapest place to normalize value objects before they hit the wire:

    $serializer->setObjectHandler(Money::class, fn (Money $m) => [
        'amount' => $m->getAmount(),
        'currency' => $m->getCurrency()->getCode(),
    ]);
    
  3. Closure handlers Register once at boot for Closure if your graph can contain them; otherwise the reflective walk will surprise you at runtime.

  4. Container binding

    $this->app->singleton(JsonSerializer::class, function () {
        $serializer = new JsonSerializer();
        $serializer->setDateTimeHandler(fn ($d) => $d->format(DATE_ATOM));
        return $serializer;
    });
    

    A singleton with handlers pre-registered beats scattering setObjectHandler across controllers.

Pro Tips

  • Pin the patch version in service boundaries — ^3.2.5 in composer.json, and treat any 3.2.x bump as a release that needs the matrix test to pass.
  • Combine with Laravel's Response:
    return response()->json($serializer->unserialize($cached), 200, [], JSON_UNESCAPED_UNICODE);
    
    Note response()->json() encodes arrays natively — don't double-encode by passing an already-serialized string unless a consumer demands a string body.
  • Test edge cases: null, false, NAN, INF, resources, and uninitialized typed properties. Run the suite on your lowest supported PHP minor, not just the newest.
  • Watch the repo, not just the tag — issues #76, #77 and #82 were all fixed by the 3.2.5 patch; a quick scan of the tracker between releases tells you whether an upgrade is cosmetic or load-bearing.
  • Cache serialized results for hot reads, keyed by model ID plus a version/updated_at component so stale payloads expire on write.
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.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc