Re: [RFC][Discussion] Add #[NoSerialize] attribute for excluding properties or classes from serialization
Hi Dmytro
On Tue, Oct 28, 2025 at 12:00 AM Dmytro Kulyk <lnkvisitor.ts@gmail.com> 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.
> 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 {}
> 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.
> Invalid Targets & Compile-Time Diagnostics
What's the rationale for warning for some, but erroring for others?
Ilija
Thread (16 messages)