Re: [RFC][Discussion] Add #[NoSerialize] attribute for excluding properties or classes from serialization

From: Date: Wed, 29 Oct 2025 15:34:53 +0000
Subject: Re: [RFC][Discussion] Add #[NoSerialize] attribute for excluding properties or classes from serialization
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to internals+get-128998@lists.php.net to get a copy of this message
Hi

Thank you for your RFC. It is really well-written and nicely explains the various (edge) cases. I've only read through the #[\NoSerialize] one, since it is the topic of this RFC discussion. I agree with Ilija on all points.

Am 2025-10-29 15:35, schrieb Dmytro Kulyk:
#[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.
But even for wrappers you can't guarantee that the wrapper is stored in a nullable property. When applying the attribute to a field, omitting the field makes sense, since the author of the property is the same person who is capable of adding the attribute and thus is in full control. This is different for classes where the author of the class doesn't know how and where the class is being used. I thus agree with Ilija that this should throw to clearly indicate that the user of the class is doing something incorrect and to not silently corrupt data. If an author of a class needs more fine-grained control, they can either add the attribute to individual properties themselves - or implement __serialize().
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. Indeed, however the “unless explicitly overridden” bit in the RFC text implies that this is possible.
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].
I don't think that sub classes should be able to make a non-serializable parent class serializable, since they clearly won't be able to correctly restore the state of the parent class. In fact I would consider this an improvement over the existing serialization hooks where the child class can simply skip calling the parent's serializer and thus create a situation that the parent class does not expect to occur.
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.
Yes, every clear error that is detectable at compile-time should be a hard error to make it easy for users to detect the mistake. Best regards Tim Düsterhus

Thread (16 messages)

« previous php.internals (#128998) next »