Signature
unserialize(string $data, array $options = []): mixedPurpose
unserialize() takes a string created by serialize() and turns it back into a PHP value. The value can be a boolean, integer, float, string, array or object. It is useful when you need to restore PHP-specific data that you stored yourself, such as a cached array or an internal object snapshot.
The format is PHP-specific and can describe objects, so it is not a general exchange format. For data that comes from users or other systems, JSON is normally the safer choice.
Signature
Parameters and defaults
$datais a single serialized value. If it describes an object, PHP calls__unserialize()or__wakeup()after rebuilding it, when the class defines one.$optionsis an associative array and defaults to an empty array. Two keys are documented:allowed_classesis an array of class names,trueorfalse. Omitting it behaves liketrue, so any class may be instantiated. Withfalse, or with a class that is not in the list, objects become__PHP_Incomplete_Classinstances. The option does not affect enumerations.max_depthis an integer limiting how deeply structures may nest, to guard against stack overflows. The default is 4096, and0disables the limit.
Return value and failure cases
On success you get the rebuilt value. If the string cannot be unserialized, the function returns false and raises E_WARNING. PHP 8.3 changed this from E_NOTICE to E_WARNING. PHP 8.3 also warns when the input has unconsumed data after the first value.
Since PHP 8.4, an allowed_classes value that is neither a bool nor an array of class names throws TypeError and ValueError. Objects can also throw their own exceptions from their unserialization handlers.
PHP 8.4 deprecates the uppercase S string tag in serialized data. Use the lowercase s form.
Example 1: a round trip
The first example serializes an array, prints the stored text, then restores it and prints it as JSON for predictable formatting.
$data = ['name' => 'Ada', 'tags' => ['php', 'json'], 'active' => true];
$text = serialize($data);
echo $text, "\n";
$copy = unserialize($text);
echo json_encode($copy, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";a:3:{s:4:"name";s:3:"Ada";s:4:"tags";a:2:{i:0;s:3:"php";i:1;s:4:"json";}s:6:"active";b:1;}
{"name":"Ada","tags":["php","json"],"active":true}
Each piece of the text carries a type and often a length, for example s:3:"Ada" for a three-byte string.
Example 2: telling failure from a stored false
Because false is both the error result and a legitimate value, checking the result alone is not enough. One approach is a temporary error handler that records whether a warning occurred.
function decode(string $text): array {
$warned = false;
set_error_handler(function () use (&$warned) {
$warned = true;
return true;
});
$value = unserialize($text);
restore_error_handler();
return ['value' => $value, 'warned' => $warned];
}
echo json_encode(decode(serialize(false))), "\n";
echo json_encode(decode('not serialized')), "\n";{"value":false,"warned":false}
{"value":false,"warned":true}
Both calls return false, but only the invalid string triggers a warning. You can also compare the input with serialize(false) before decoding.
Example 3: restricting classes
Object instantiation is the risky part of unserialization. The allowed_classes option lets you decide which classes may be created.
class Point {
public function __construct(public int $x = 0, public int $y = 0) {}
}
$text = serialize(new Point(1, 2));
echo $text, "\n";
$safe = unserialize($text, ['allowed_classes' => false]);
echo get_class($safe), "\n";
$point = unserialize($text, ['allowed_classes' => ['Point']]);
echo get_class($point), ' ', $point->x + $point->y, "\n";O:5:"Point":2:{s:1:"x";i:1;s:1:"y";i:2;}
__PHP_Incomplete_Class
Point 3
With false, the data is not turned into a Point; you receive an incomplete-class placeholder instead. With an explicit list, the allowed class is restored normally.
Edge cases
- A stored
falseand a failure look the same in the return value, so decide how to distinguish them. - Trailing data after a valid value produces a warning as of PHP 8.3.
- Undefined classes become
__PHP_Incomplete_Classunless theunserialize_callback_funcdirective supplies a way to load them. - Deeply nested input can hit
max_depth. Lowering it is reasonable if you know your data is shallow. - Autoloading can run during object creation, which is one reason class restrictions matter.
Common mistakes
- Unserializing untrusted input. The manual warns not to pass untrusted user input to
unserialize(), even withallowed_classes. Object instantiation and autoloading can lead to code being loaded and executed. Usejson_decode()for data that crosses a trust boundary. - Assuming
falsealways means an error. A serializedfalsedecodes tofalsewithout any warning. - Leaving
allowed_classesunset. Omitting it is the same as allowing every class. - Passing a wrong option type in PHP 8.4. A value such as a string for
allowed_classesnow throws instead of merely failing. - Editing serialized strings by hand. String lengths are part of the format, so changing text without updating its length breaks the data.
- Skipping integrity checks for stored data. If serialized data lives outside your process, the manual suggests validating it with
hash_hmac()so nobody else can modify it.
Related functions
serialize()creates the string thatunserialize()reads.json_encode()andjson_decode()are the safer, portable alternative.hash_hmac()helps verify that stored data was not tampered with.- The magic methods
__serialize(),__unserialize()and__wakeup()customize object handling.
Recap
unserialize() restores a value from a string made by serialize(). It returns false with a warning on failure, but false can also be a valid result. Use allowed_classes to limit object creation, max_depth to limit nesting, and never feed it untrusted input. Prefer JSON when data comes from outside your own code.
Tested examples
$data = ['name' => 'Ada', 'tags' => ['php', 'json'], 'active' => true];
$text = serialize($data);
echo $text, "\n";
$copy = unserialize($text);
echo json_encode($copy, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";
a:3:{s:4:"name";s:3:"Ada";s:4:"tags";a:2:{i:0;s:3:"php";i:1;s:4:"json";}s:6:"active";b:1;}
{"name":"Ada","tags":["php","json"],"active":true}
function decode(string $text): array {
$warned = false;
set_error_handler(function () use (&$warned) {
$warned = true;
return true;
});
$value = unserialize($text);
restore_error_handler();
return ['value' => $value, 'warned' => $warned];
}
echo json_encode(decode(serialize(false))), "\n";
echo json_encode(decode('not serialized')), "\n";
{"value":false,"warned":false}
{"value":false,"warned":true}
class Point {
public function __construct(public int $x = 0, public int $y = 0) {}
}
$text = serialize(new Point(1, 2));
echo $text, "\n";
$safe = unserialize($text, ['allowed_classes' => false]);
echo get_class($safe), "\n";
$point = unserialize($text, ['allowed_classes' => ['Point']]);
echo get_class($point), ' ', $point->x + $point->y, "\n";
O:5:"Point":2:{s:1:"x";i:1;s:1:"y";i:2;}
__PHP_Incomplete_Class
Point 3