Serialization is a fundamental mechanism in PHP that allows objects to be converted into a storable or transferable representation.
However, not every property of an object should necessarily be serialized. Frameworks and libraries often contain transient or resource-based properties—such as database connections, file handles, or caches—that should not be persisted.
Currently, developers must manually handle this by overriding __sleep()
or __serialize()
, which can lead to repetitive boilerplate and maintenance overhead.
This proposal introduces a new #[NoSerialize]
attribute that can be applied to class properties to exclude them from native PHP serialization explicitly.
It provides a declarative alternative to manually filtering properties within __sleep()
or __serialize()
, making serialization rules easier to maintain and more self-documenting.
<?php use Attribute; /** * Marks a property as excluded from native serialization. * * When applied, this property will not appear in the output * of serialize(), nor be restored during unserialize(). */ #[Attribute(Attribute::TARGET_PROPERTY)] final class NoSerialize {} ?>
Usage example:
<?php class Example { public string $name; #[NoSerialize] public PDO $connection; } $object = new Example(); $object->name = "User"; $object->connection = new PDO('sqlite::memory:'); echo serialize($object); // Serialized output will be `O:7:"Example":1:{s:4:"name";s:4:"User";}`. ?>
serialize()
is invoked and the class does not define its own __serialize()
or __sleep()
, properties marked with #[NoSerialize]
are skipped automatically.#[NoSerialize]
attribute does not affect deserialization — if a property exists in the serialized data (e.g., produced by an older version of the class or by userland code), it will be deserialized.class SessionWrapper { public string $id; #[NoSerialize] public $resource; // transient field public function __construct() { $this->resource = fopen('php://memory', 'r+'); } } $s = new SessionWrapper(); $s->id = 'abc'; var_dump(unserialize(serialize($s))); /* object(SessionWrapper)#2 (1) { ["id"]=> string(3) "abc" } */
If a class defines its own serialization logic via __serialize()
or __sleep()
, the #[NoSerialize]
attribute has no effect.
These methods are entirely user-defined, and PHP does not automatically filter out attributes marked with #[NoSerialize]
.
This design maintains explicit and consistent behavior with existing PHP semantics — developer code always takes precedence when custom serialization is implemented.
Example:
class Custom { public string $a = 'A'; #[NoSerialize] public string $b = 'B'; public function __serialize(): array { return ['a' => $this->a, 'b' => $this->b]; } } echo serialize(new Custom()); // Output still contains both 'a' and 'b'
Developers who wish to honor #[NoSerialize]
within a custom __serialize()
can do so manually using reflection:
class Custom { public string $a = 'A'; #[NoSerialize] public string $b = 'B'; public function __serialize(): array { $result = []; foreach ((new ReflectionObject($this))->getProperties() as $prop) { if (!$prop->getAttributes(NoSerialize::class)) { $prop->setAccessible(true); $result[$prop->getName()] = $prop->getValue($this); } } return $result; } }
#[NoSerialize]
applies only to the declaring property and is not inherited when a child class redeclares the same property.class Example { public function __construct( public string $name, #[NoSerialize] public ?PDO $db = null ) {} }
serialize()
, unserialize()
).The attribute is visible and queryable via reflection:
$rp = new ReflectionProperty(Example::class, 'connection'); var_dump($rp->getAttributes(NoSerialize::class)); // array(1) { ... }
Applying #[NoSerialize]
to static or virtual properties is not meaningful for native serialization. The engine will therefore emit compile-time warnings and ignore the attribute in these cases.
Engine messages (proposed):
NoSerialize can no longer be used as a class name in the global namespace. A GitHub search for “class NoSerialize” language:php revealed only one match in source code. The class is defined within a namespace.
Next version of PHP (PHP 8.6 or PHP 9.0)
What effect will the RFC have on IDEs, Language Servers (LSPs), Static Analyzers, Auto-Formatters, Linters and commonly used userland PHP libraries?
None
None
Make sure there are no open issues when the vote starts!
Pick a title that reflects the concrete choice people will vote on.
Please consult the php/policies repository for the current voting guidelines.
After the RFC is implemented, this section should contain: - the version(s) it was merged into - a link to the git commit(s) - a link to the PHP manual entry for the feature
Links to external references, discussions, or RFCs.
Keep this updated with features that were discussed on the mail lists.
If there are major changes to the initial proposal, please include a short summary with a date or a link to the mailing list announcement here, as not everyone has access to the wikis' version history.