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.

> 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

Reply via email to