Replacing PHP serialize() with JSON for Enhanced Performance and Security

Replacing PHP serialize() with JSON for Enhanced Performance and Security
Replacing PHP serialize() with JSON for Enhanced Performance and Security

Upgrade your PHP application by switching from serialize() to JSON for faster, safer, and more efficient data handling across different platforms.

Here’s the scenario that ends careers: you pull a value from a cookie, a form field, or a cache row an attacker can reach, and you hand it straight to unserialize(). If your codebase has the wrong class loaded, that one line becomes remote code execution. This is not theory. PHP object injection through unserialize() is a well-documented attack class, and it’s the real reason to reach for JSON.

So let’s be honest about what this switch actually buys you. It’s mostly about safety and interoperability, not speed. In this guide we’ll compare serialize() and JSON, show how to convert existing code, and be clear about what you give up when you switch. Because you do give up something, and anyone who tells you otherwise hasn’t hit the edge cases yet.

Why Move from serialize() to JSON?

serialize() works fine. It’s fast, it’s built in, and it round-trips PHP data with more fidelity than JSON does. The case for JSON isn’t that serialize() is broken. It’s that JSON is better suited to a few specific jobs:

  • Security with untrusted data: This is the big one. unserialize() can instantiate objects and trigger their magic methods (__wakeup(), __destruct()), which opens the door to object injection and, in the wrong codebase, remote code execution. json_decode() never instantiates arbitrary objects. It only produces arrays, scalars, and plain stdClass. If the data came from anywhere a user can touch, that difference matters more than anything else on this list.
  • Interoperability: JSON is understood by almost every language and platform. serialize() output is PHP-only. If another system needs to read your data, JSON is the obvious choice.
  • Readability: JSON is human-readable. Serialized strings, with their length prefixes and type tags, are not fun to debug by eye.
  • Frontend compatibility: JavaScript parses JSON natively, so passing data to the browser is one step, not two.

Notice what’s not on that list: performance. We’ll get to why below.

Basic Syntax: serialize() vs JSON

Before the advanced cases, let’s compare the two side by side. First, serializing an array with serialize().

Example: Using serialize() to Convert an Array to a String
PHP
<?php
$data            = ['name' => 'John', 'age' => 30, 'email' => '[email protected]'];
$serialized_data = serialize( $data );
echo $serialized_data;

Output:

a:3:{s:4:"name";s:4:"John";s:3:"age";i:30;s:5:"email";s:17:"[email protected]";}

Useful for storage, but not something you’d want to read at 2am during an incident. Now the same data as JSON.

Example: Using json_encode() to Convert an Array to a JSON String
PHP
<?php
$data      = ['name' => 'John', 'age' => 30, 'email' => '[email protected]'];
$json_data = json_encode( $data );
echo $json_data;

Output:

{"name":"John","age":30,"email":"[email protected]"}

Cleaner, and any JavaScript client can read it as-is.

Understanding the Differences Between serialize() and JSON

The core difference: serialize() is a PHP-native format that preserves PHP semantics, while JSON is a language-agnostic interchange format that flattens everything to arrays and scalars. That framing explains every trade-off below.

  • Type fidelity: serialize() preserves exact types, object classes, private and protected properties, and internal references between values. JSON keeps none of that. It gives you back arrays, strings, numbers, booleans, and null. Objects come back as stdClass (or associative arrays if you pass true), with the original class and visibility gone.
  • What each can’t handle: Neither format can serialize a PHP resource (a file handle, a database connection). The PHP manual is explicit that serialize() handles all types except the resource type and certain objects such as closures. JSON also can’t represent objects unless you convert them yourself.
  • Float precision: serialize() round-trips floats exactly. JSON can lose precision on some floating-point values depending on your serialize_precision setting, so don’t assume a decoded float equals the one you encoded.
  • Cross-language usability: JSON is readable almost everywhere. serialize() is PHP-only.
  • Security: Covered above, and it’s the deciding factor for untrusted input. unserialize() can instantiate objects; json_decode() cannot.
Converting Serialized Data to JSON

If you have a codebase using serialize() for plain arrays, the swap is mechanical. Here’s a file-storage example.

Example: Refactoring Serialized Data to JSON
Original Code Using serialize()
PHP
<?php
$data            = ['name' => 'Alice', 'role' => 'admin'];
$serialized_data = serialize( $data );
// Store serialized data in a file
file_put_contents( 'data.txt', $serialized_data );
// Retrieve and unserialize the data
$retrieved_data = unserialize( file_get_contents( 'data.txt' ) );
print_r( $retrieved_data );
Refactored Code Using json_encode() and json_decode()
PHP
<?php
$data      = ['name' => 'Alice', 'role' => 'admin'];
$json_data = json_encode( $data );
// Store JSON data in a file
file_put_contents( 'data.json', $json_data );
// Retrieve and decode the JSON data
$retrieved_data = json_decode( file_get_contents( 'data.json' ), true );
print_r( $retrieved_data );

Passing true as the second argument to json_decode() gives you an associative array instead of a stdClass object, which usually maps cleaner onto code that expected the old unserialize() array. One caveat when migrating: existing files written by serialize() won’t be readable by json_decode(), so plan a migration path for data already on disk.

Handling Object Serialization

This is where the honesty matters. serialize() can persist a whole object, class and all, and bring it back intact. JSON can’t. If you’re storing objects, you have to decide how each one becomes plain data, and how it gets rebuilt. The simplest approach is a method that returns an array.

Example: Converting an Object to JSON
PHP
<?php
class User {
    public $name;
    public $email;
    public function __construct( $name, $email ) {
        $this->name  = $name;
        $this->email = $email;
    }
    // Convert the object to an array for JSON encoding
    public function toArray() {
        return get_object_vars( $this );
    }
}
$user      = new User( 'Bob', '[email protected]' );
$json_user = json_encode( $user->toArray() );
echo $json_user;

The toArray() method flattens the object’s properties into an array that json_encode() can handle. For cleaner control, implement the JsonSerializable interface so json_encode() knows how to handle your object directly. Either way, remember: decoding gives you data, not a User. You’re responsible for turning it back into one.

Performance Considerations

You’ll often read that JSON is faster. Sometimes it is. In many cases json_encode() and json_decode() do edge out serialize() and unserialize(), but the gap depends on your PHP version, your data shape, and your workload. It swings both ways, and it’s usually small enough that it shouldn’t drive the decision. Choose JSON for safety and interoperability, not because you’re chasing microseconds. If performance genuinely matters for your case, measure it on your own data.

Benchmarking serialize() vs JSON
PHP
<?php
$data = array_fill( 0, 10000, ['name' => 'John', 'age' => 30] );
// Benchmark serialize()
$start           = microtime( true );
$serialized_data = serialize( $data );
$end             = microtime( true );
echo 'serialize(): ' . ( $end – $start ) . ' seconds';
// Benchmark json_encode()
$start     = microtime( true );
$json_data = json_encode( $data );
$end       = microtime( true );
echo 'json_encode(): ' . ( $end – $start ) . ' seconds';

Run this on your own hardware and PHP version before you draw conclusions. A single micro-benchmark on synthetic data won’t tell you how either function behaves on your real payloads.

Best Practices for Using JSON in PHP
  • Fail loudly on bad data: Pass the JSON_THROW_ON_ERROR flag (PHP 7.3+) so a malformed payload throws a JsonException instead of silently returning null. If you can’t use it, check json_last_error() after every encode and decode.
  • Pick a return shape and stick to it: Pass true to json_decode() for associative arrays, or leave it off for objects. Be consistent so callers know what they’re getting.
  • Never unserialize untrusted input: If the data is anything a user can influence, don’t feed it to unserialize(). Use json_decode(). If you must use unserialize() on semi-trusted data, pass ['allowed_classes' => false] to block object instantiation.
  • Keep serialize() for trusted internal state: If you control both ends, the data never leaves PHP, and you need object or type fidelity, serialize() is still the right tool. Switching to JSON there just costs you fidelity for no gain.
Conclusion

The clean rule: use JSON for anything untrusted or anything that crosses a language boundary, and keep serialize() for trusted, PHP-only data where you need to preserve object types and precise values. JSON’s headline win is security against object injection, with interoperability and readability close behind. Performance is a wash and shouldn’t decide it. Know what JSON drops (object classes, private properties, exact types, references) and convert your objects deliberately. Get those trade-offs right and the switch makes your code safer without any nasty surprises down the line.

Leave a Comment

Your email address will not be published. Required fields are marked *


Scroll to Top