Thanks for the feedback!

On Tue, Oct 28, 2025 at 17:47 Ilija Tovilo <[email protected]> wrote:
>
> Hi Dmytro
>
> On Tue, Oct 28, 2025 at 12:00 AM Dmytro Kulyk <[email protected]> wrote:
> >
> > I’d like to open a discussion about a new proposal introducing the
> > #[NoSerialize] attribute, which allows developers to explicitly
> > exclude properties — or even entire classes — from native PHP
> > serialization.
> >
> > RFC: https://wiki.php.net/rfc/no_serialize_attribute
> > Implementation: https://github.com/php/php-src/pull/20074
>
> Thank you for your proposal. I have a few comments.
>
> > When applied to a class, instances will be serialized as NULL.
>
> I don't understand the rationale for diverging from the existing
> @not-serializable behavior of internal classes, which throw when
> attempted to be serialized (e.g. Random\Engine\Secure). I see there's
> also a separate RFC to introduce that behavior:
> https://wiki.php.net/rfc/not_serializable_attribute I don't think
> there's a need for both of these attributes. To demonstrate, how would
> we even decide whether an internal class like PDO should get the
> #[NoSerialize] or #[NotSerializable] attribute? Informing the user of
> potentially incorrect serialization is the prudent option, and if they
> would like to skip the serialization of a property containing a PDO
> object they can simply mark it as #[NoSerialize].
>
> The RFC says:
>
> > This approach ensures that data structures containing such objects (for 
> > example, arrays, collections, or parent objects) remain valid and can be 
> > safely unserialized without errors, while clearly indicating that the value 
> > was intentionally omitted.
>
> But is replacing unserializable objects with NULL in nested arrays
> really the safe choice? In these cases, I feel like a custom
> serializer that consciously replaces the object is warranted. This
> might also cause problems for typed properties:
>
>     #[NoSerialize]
>     class PDO {}
>
>     class Foo {
>         /* Will be happily serialized as NULL, but can't be restored because 
> the
>          * property is not nullable. */
>         public PDO $connection;
>     }
>
> To summarize, I'd prefer if #[NoSerialize] on classes would cause
> serialize() to throw, like we already do for @not-serializable.

You’re absolutely right that the current internal behavior (e.g.
Random\Engine\Secure, CurlHandle, etc.) throws when serialization is
attempted, and that the proposed #[NotSerializable] RFC formalizes
this for userland classes.
The intent behind #[NoSerialize] is not to diverge from that model,
but to provide a softer, complementary mechanism targeting a different
use case — non-critical, transient classes that can safely degrade to
NULL without breaking surrounding data structures.
In this example, PDO (and other resource-backed classes) should indeed
use #[NotSerializable], because serialization is semantically invalid
and must throw.
#[NoSerialize], on the other hand, would apply to wrappers,
containers, or domain objects where serialization of the rest of the
structure should continue even if one field or nested object cannot be
meaningfully serialized.

>
> > Class-level #[NoSerialize] is inherited by child classes unless explicitly 
> > overridden.
>
> Can you clarify how this would work? How can you override this
> attribute by omission?
>
>     #[NoSerialize]
>     class Foo {}
>
>     /* What do I add here to remove #[NoSerialize]? */
>     class Bar extends Foo {}

Class-level #[NoSerialize] is transparently inherited by child classes.
There’s currently no way to override or cancel this behavior in
descendants; the attribute remains effective throughout the
inheritance chain.


As an alternative, #[NotSerializable] could be extended to
#[NotSerializable(bool $soft = false)], which would provide the same
behavior while keeping it in a separate, more consistent attribute —
avoiding the double semantics currently implied by #[NoSerialize].

> > Out of scope: JSON (json_encode(), JsonSerializable) and var_export() 
> > remain unaffected.
>
> Any future attempt to exclude properties marked as #[NoSerialize] from
> json_encode() would be backwards incompatible after this RFC has been
> implemented. To avoid this BC break, json_encode() would need a
> separate attribute (e.g. #[NoJsonEncode]). That sounds reasonable, but
> should be spelled out in the RFC.

It has been added to section 2.5

> > Invalid Targets & Compile-Time Diagnostics
>
> What's the rationale for warning for some, but erroring for others?

Initially, the idea was to make all of these cases emit warnings, but
I didn’t figure out how to implement that consistently within the
attribute validators.
At this point, I don’t see any practical reason to allow the attribute
on unsupported targets, so all such cases will be changed to
compile-time errors instead of warnings.

Dmytro

Reply via email to