Types7 min readExamples run on PHP 8.5.10

serialize()

Learn how PHP 8.4 serialize() converts values to a storable string, how objects and references behave, and which mistakes to avoid.

Signature

serialize(mixed $value): string

Purpose

serialize() converts a PHP value into a string that records both the data and its type. You can keep that string in a cache entry, queue message or database column, and later rebuild the value with unserialize(). Unlike a plain (string) cast, the result keeps the difference between 42 and "42", between false and null, and the full shape of nested arrays.

Signature

Parameters

$value is the only parameter and has no default. It accepts any type except resources, and some objects cannot be serialized either. Arrays and objects are walked recursively. Circular references inside the structure being serialized are preserved. Any other reference is lost, so two variables that were bound by reference come back as independent values.

Return value and failures

The function returns a string. The manual stresses that it is a binary string that may contain null bytes, so store it in a BLOB-style column rather than a CHAR or TEXT field. Strings are recorded with their length in bytes, not characters.

The string format is compact. i:42; is an integer, b:1; is true, d:3.5; is a float, N; is null, and s:5:"..."; is a five-byte string. Arrays start with a: and a count, and objects start with O:, the class name length and the class name.

Built-in objects that implement none of Serializable, __serialize()/__unserialize() or __sleep()/__wakeup() cannot reliably be serialized. In that case, expect an error instead of a usable string. Closures are a common example.

Example 1: scalar values

Each type has its own prefix. Note that café is five bytes in UTF-8 because é takes two.

Example
<?php
echo serialize(true), "\n";
echo serialize(42), "\n";
echo serialize(3.5), "\n";
echo serialize("café"), "\n";
echo serialize(null), "\n";
Output
b:1;
i:42;
d:3.5;
s:5:"café";
N;

Example 2: a round trip with an array

Nested arrays keep their keys, order and value types. Because the types are preserved, a strict comparison after unserialize() succeeds.

Example
<?php
$data = ['id' => 7, 'tags' => ['php', 'json'], 'active' => false];
$text = serialize($data);
echo $text, "\n";
var_dump(unserialize($text) === $data);
Output
a:3:{s:2:"id";i:7;s:4:"tags";a:2:{i:0;s:3:"php";i:1;s:4:"json";}s:6:"active";b:0;}
bool(true)

Example 3: controlling object output

When an object defines __serialize(), PHP calls it and serializes the returned array. This lets you choose exactly which data is stored, and avoids the null-byte prefixes that private and protected property names otherwise receive. The matching __unserialize() receives that array when the value is restored.

Example
<?php
final class Point
{
    public function __construct(private int $x, private int $y) {}

    public function __serialize(): array
    {
        return ['x' => $this->x, 'y' => $this->y];
    }

    public function __unserialize(array $data): void
    {
        $this->x = $data['x'];
        $this->y = $data['y'];
    }
}

echo serialize(new Point(3, 4)), "\n";
Output
O:5:"Point":2:{s:1:"x";i:3;s:1:"y";i:4;}

Edge cases

  • Private and protected properties: without __serialize(), a private property name is prefixed with the class name and a protected one with *, each surrounded by null bytes. Printing or copying such a string as text can corrupt it.
  • Namespaced classes: the leading backslash is left out of the stored class name for compatibility.
  • Byte lengths: the number in s:N: counts bytes. Editing a serialized string by hand, or converting its encoding, breaks it.
  • References: only circular references within the serialized structure survive. Other reference relationships are flattened into copies.
  • Resources: database connections, file handles and similar values cannot be stored. Store the information needed to reopen them instead.

Common mistakes

  1. Using it as an interchange format. The format is PHP-specific. If other languages must read the data, json_encode() is usually a better choice.
  2. Calling unserialize() on untrusted input. Restoring attacker-controlled strings can instantiate classes and trigger magic methods. Prefer JSON for external data, or restrict classes with the allowed_classes option of unserialize().
  3. Storing the result in a text column. Null bytes and byte-oriented lengths make TEXT storage unreliable. Use a binary-safe column.
  4. Expecting references to survive. Do not rely on shared references being rebuilt after a round trip.
  5. Serializing live objects wholesale. Objects holding connections, closures or large caches should limit their stored state with __serialize() or __sleep().
  6. Treating the format as stable across class changes. If you rename a class or change its properties, previously stored strings may no longer restore as you expect. Plan a migration.
  • unserialize() rebuilds a PHP value from the string.
  • json_encode() produces portable text for arrays and simple objects.
  • var_export() returns parsable PHP code for a value.
  • The magic methods __serialize(), __unserialize(), __sleep() and __wakeup() customize object behavior.

Recap

serialize(mixed $value): string produces a type-preserving, binary-safe string for nearly any PHP value. It keeps nested structure and circular references but not ordinary references, and it cannot handle resources or some built-in objects. Use __serialize() to control object contents, store the output in a binary-safe place, and never unserialize untrusted data without strict safeguards.

Tested examples

Serializing scalar values
<?php
echo serialize(true), "\n";
echo serialize(42), "\n";
echo serialize(3.5), "\n";
echo serialize("café"), "\n";
echo serialize(null), "\n";
Output
b:1;
i:42;
d:3.5;
s:5:"café";
N;
Round trip with a nested array
<?php
$data = ['id' => 7, 'tags' => ['php', 'json'], 'active' => false];
$text = serialize($data);
echo $text, "\n";
var_dump(unserialize($text) === $data);
Output
a:3:{s:2:"id";i:7;s:4:"tags";a:2:{i:0;s:3:"php";i:1;s:4:"json";}s:6:"active";b:0;}
bool(true)
Controlling object output with __serialize()
<?php
final class Point
{
    public function __construct(private int $x, private int $y) {}

    public function __serialize(): array
    {
        return ['x' => $this->x, 'y' => $this->y];
    }

    public function __unserialize(array $data): void
    {
        $this->x = $data['x'];
        $this->y = $data['y'];
    }
}

echo serialize(new Point(3, 4)), "\n";
Output
O:5:"Point":2:{s:1:"x";i:3;s:1:"y";i:4;}