Thanks for the feedback!
On Tue, Oct 28, 2025 at 17:47 Ilija Tovilo <tovilo.ilija@gmail.com> wrote:
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: PHP: rfc:no_serialize_attribute
> Implementation: Add `#[NoSerialize]` attribute support to prevent property serialization. by dkulyk · Pull Request #20074 · php/php-src · GitHub
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:
PHP: 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