Object serialization — serialize(), unserialize(), __sleep, __wakeup, Serializable
Concept
PHP's serialize() and unserialize() convert objects to and from a portable string representation. This is used for caching, session storage, and data transfer — but comes with significant security considerations.
serialize($value) produces a PHP-specific format string: O:4:"User":2:{s:4:"name";s:5:"Alice";s:3:"age";i:30;}. It includes the class name, property names, and values recursively. Static properties are excluded. Resources cannot be serialized.
unserialize($str, $options): Reconstructs the object from the string. In PHP 7.0+, always pass ['allowed_classes' => ['ClassName', ...]] or ['allowed_classes' => false] to prevent PHP object injection attacks. Without this restriction, unserializing user-supplied data can trigger arbitrary __wakeup/__destruct calls.
__sleep(): Called before serialization. Return an array of property names to include in the serialized form. Use to exclude sensitive data (passwords, tokens) or resource handles.
__wakeup(): Called after unserialization. Use to reinitialize resources that couldn't be serialized (database connections, file handles).
Modern alternative: Serializable interface (deprecated in PHP 8.1) — serialize() method returns a string, unserialize() restores from it. Now replaced by __serialize() / __unserialize() (PHP 7.4+) which work with arrays instead of raw strings — cleaner and more explicit.
Security: Never unserialize() user-supplied data without allowed_classes. PHP object injection vulnerabilities exploit __wakeup or __destruct on unexpected classes.
Code Example
<?php
declare(strict_types=1);
class SessionData
{
private string $password = 'secret'; // should NOT be serialized
public function __construct(
private string $username,
private array $permissions = [],
) {}
// Exclude password from serialization
public function __sleep(): array
{
return ['username', 'permissions']; // only these properties serialized
}
public function __wakeup(): void
{
// Re-initialize anything that needed to be excluded
// e.g., reconnect to a database, reload config
echo "Woken up: {$this->username}\n";
}
}
$data = new SessionData('alice', ['read', 'write']);
$serialized = serialize($data);
echo $serialized;
// O:11:"SessionData":2:{s:8:"username";s:5:"alice";s:11:"permissions";...}
// Safe unserialize with allowed_classes
$restored = unserialize($serialized, ['allowed_classes' => ['SessionData']]);
echo $restored instanceof SessionData ? "OK\n" : "Failed\n";
// Modern alternative: __serialize / __unserialize (PHP 7.4+)
class Token
{
private string $secret;
public function __construct(private string $value, string $secret)
{
$this->secret = hash_hmac('sha256', $value, $secret);
}
public function __serialize(): array
{
return ['value' => $this->value]; // don't include the secret
}
public function __unserialize(array $data): void
{
$this->value = $data['value'];
$this->secret = ''; // will need to be re-set
}
}
// Security: block object injection
$malicious = 'O:8:"Anything":0:{}';
$safe = unserialize($malicious, ['allowed_classes' => false]);
// Returns stdClass, NOT an instance of "Anything"
// For cache storage, prefer JSON or igbinary (smaller, faster)
$json = json_encode(['class' => 'SessionData', 'username' => 'alice']);
// But JSON can't represent objects with methods — use for data only