Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127388 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id EFD781A00BC for ; Fri, 16 May 2025 09:33:21 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1747387871; bh=/YB/uZgv8iOapSp1/pO3kvGMDR+qQ8oyjmexT3lsdGg=; h=Date:From:To:In-Reply-To:References:Subject:From; b=cqEJGXAfvnP8xKn1d6UQQknwRQ0h3DsFhuuoNeWemajjg261NmR8tqTgRMjU6F1rA RaABkIgDqdVP1MP+/GFMb2AHKxjOin8PggFGhVqrR/6/sYavrYll5RZaW+Xr4niXGK DL4pNAMWKu2Negus15Z4/TDgN88N/6yQydRkSc4+g4MV+BhadfqSa9Dt108M5pOO96 evaf8nGlWSZPSex/O7eW4/ijcI4ityJmSpubYSSCRyZC/eezCS27FSnEHCVwhFVLR9 AmBOL33TSRYJqcTE7nYzK3/eFXZbmy4JEnMidE6GIax04659hZ+uaTfj4e+QkBrplv WCBSZ4MVZCzNg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D9AAC180087 for ; Fri, 16 May 2025 09:31:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_20,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_MISSING,HTML_MESSAGE, RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from fhigh-b7-smtp.messagingengine.com (fhigh-b7-smtp.messagingengine.com [202.12.124.158]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Fri, 16 May 2025 09:31:09 +0000 (UTC) Received: from phl-compute-05.internal (phl-compute-05.phl.internal [10.202.2.45]) by mailfhigh.stl.internal (Postfix) with ESMTP id 3E1E325400F3 for ; Fri, 16 May 2025 05:33:19 -0400 (EDT) Received: from phl-imap-09 ([10.202.2.99]) by phl-compute-05.internal (MEProxy); Fri, 16 May 2025 05:33:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc:content-type:content-type:date:date:from:from:in-reply-to :in-reply-to:message-id:mime-version:references:reply-to:subject :subject:to:to; s=fm1; t=1747387999; x=1747474399; bh=Py0rNVDxP/ h/TqDWsovThNuszWMhDw61ViwCTzmsJqI=; b=cWYKWqyVIfKbNYcjpPHnXCcgOR uhbfnrZq0hava6Xnj+psG3FZxnZqin6Mw+adgn61eejybkUKY5khYgK2mSxyc3gL Nf3vlnRRiL7bmTpHraQ9nk/ZsaiAB+C9o634GvokeCzSXMbK889GVk5FNu5DFK+u qCGh9aClDQHpsQMTSB+ohrUwxfZASmi89wzWcOJYrZv2MUuXVlRiCh7WnMtBmXTl n/reXp//psKFu+hLH/GTaQWHLqvfzt/kQH9FbTorFAh0ieOLIfEDVrY1SVDKFjKv eiS9gpHH8N5AyhD2oyt81qhycZ7fr12l1/27rfWKtd02NcLelcMVg0Ic0lZA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-type:content-type:date:date :feedback-id:feedback-id:from:from:in-reply-to:in-reply-to :message-id:mime-version:references:reply-to:subject:subject:to :to:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm3; t= 1747387999; x=1747474399; bh=Py0rNVDxP/h/TqDWsovThNuszWMhDw61Viw CTzmsJqI=; b=Pe+YLaDBxYV2bXRrvw2G8XxOze+ihjUkv13CreqEiwILVgG3aVz 0no0CSU2xchFOksP9sKja5IjMS/0hw7N8//9jKK3CHUNSLfhFPpupaILjRqKXyq6 Iu4S/fHtijowiwhj41bF1vvCFOG7aN9OmVXuvrz8vbUGTS9RkUsXtAQ7xlIruaLZ UafG1bEMsXAXk64sfg3/dGEwCX+eJwQ9j1/uXWrBUUKMT/dD6PgGNWJwZiY4kiBc lr+OeFrZkla/jDT5UEuUUU700JTlVEV8qOYSah4FNOueq6f+rlqLj/lCN6xt1V7S 3CoVz1sMZPO/mJSDK70UmfR8C4WQ7rglX5Q== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgdefuddvfeelucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdggtfgfnhhsuhgsshgtrhhisggv pdfurfetoffkrfgpnffqhgenuceurghilhhouhhtmecufedttdenucenucfjughrpefogg ffhffvkfgjfhfutgesrgdtreerredtjeenucfhrhhomhepfdftohgsucfnrghnuggvrhhs fdcuoehrohgssegsohhtthhlvggurdgtohguvghsqeenucggtffrrghtthgvrhhnpedtue ejtdethfeulefhtdelieduteelffdtudelheffgedtieehhfelieejgfevgeenucevlhhu shhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehrohgssegsohhtth hlvggurdgtohguvghspdhnsggprhgtphhtthhopedupdhmohguvgepshhmthhpohhuthdp rhgtphhtthhopehinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvght X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id AC3C1302005F; Fri, 16 May 2025 05:33:18 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: Ta3b79d818733aba6 Date: Fri, 16 May 2025 11:32:58 +0200 To: internals@lists.php.net Message-ID: In-Reply-To: References: <266FA35A-15B0-435E-BBFE-1C6926EB0B7E@koalephant.com> <74fde04e-1cbf-423c-8b50-7d7eb156a056@app.fastmail.com> <9c9d0541-381c-4fa9-8267-2492113f6fa2@app.fastmail.com> Subject: Re: [PHP-DEV] [RFC] Clone with v2 Content-Type: multipart/alternative; boundary=ceef4687e23e4f6494b7a58f5f58bd73 From: rob@bottled.codes ("Rob Landers") --ceef4687e23e4f6494b7a58f5f58bd73 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Thu, May 15, 2025, at 22:11, Larry Garfield wrote: > On Thu, May 15, 2025, at 2:56 PM, Rob Landers wrote: > > On Thu, May 15, 2025, at 17:32, Tim D=C3=BCsterhus wrote: > >> Hi > >>=20 > >> Am 2025-05-15 14:14, schrieb Rob Landers: > >> > For example, if you have a Money type, you'd want to be able to e= nsure=20 > >> > it cannot be negative when updating via `with()`. This is super=20 > >> > important for ensuring constraints are met during the clone. > >>=20 > >> That's why the assignments during cloning work exactly like regular=20 > >> property assignments, observing visibility and property hooks. > >>=20 > >> The only tiny difference is that an =E2=80=9Coutsider=E2=80=9D is a= ble to change a=20 > >> `public(set) readonly` property after a `__clone()` method ran to=20 > >> completion and relied on the property in question not changing on t= he=20 > >> cloned object after it observed its value. This seems not to be=20 > >> something relevant in practice, because why would the exact value o= f the=20 > >> property only matter during cloning, but not at any other time? > >>=20 > >> Best regards > >> Tim D=C3=BCsterhus > >>=20 > > > > Hey Tim, > > > >> why would the exact value of the=20 > >> property only matter during cloning, but not at any other time? > > > > For example, queueing up patches to store/db to commit later; during=20 > > the clone, it may register various states to ensure the patches are=20 > > accurate from that point. That's just one example, though, and it=20 > > suggests calling __clone *before* setting the values is the right=20 > > answer. > > > > I think Larry's idea of just using hooks for validation is also pret= ty=20 > > good. As Larry said, the only thing you can really do is throw an=20 > > exception, and the same would be true in a constructor as well. > > > > =E2=80=94 Rob >=20 > The limit of hooks is that they're single-property. So depending on h= ow your derived properties are implemented, it may be insufficient. I c= ould easily write such an example (the hooks RFC included some), but how= contrived they are, I don't know. >=20 > --Larry Garfield >=20 Yeah, the validation won't be too automatable (ie, in a base class) with= out at least having reusable hooks. It's important to be mindful that th= ere are approximately three different paradigms when it comes to validat= ing objects (and they apply to frameworks differently) in PHP. -- validate on serialization -- This paradigm is mostly used in symfony via doctrine/serializer. An obje= ct is allowed to be in an "invalid" state and is usually constructed in = a "zero" state, and then state is applied over the lifetime of the appli= cation. Only during serialization to the wire is it usually validated. S= o, it usually looks something like this: $user =3D new User(); $user->name =3D "Rob" $user->id =3D 123; When you receive an object in a function, you will likely have to valida= te that specific properties are set before operating on it, otherwise yo= u can end up with bugs. The nice thing about this style is that you can = build up an object's state over a longer period (such as processing a fo= rm input or a database query result). -- validate on construction -- This paradigm is commonly used in value objects and more functional-styl= e PHP. The idea is that an object must be valid by the time it is constr= ucted and does not allow partially formed objects to exist. All properti= es are validated in the constructor, and invalid combinations throw exce= ptions immediately. This tends to lead to more robust code, particularly= when the object represents a meaningful invariant (e.g., `Money`, `Emai= lAddress`, `Uuid`). Here's what it looks like: $user =3D new User(name: "Rob", id: 123); The dowside is that its harder to build objects piece by piece and usual= ly requires factories, DTOs, and builder patterns for times when not all= the data is available upfront. This approach is usually seen in functio= nal, DDD (domain driven design), or strict typing contexts and plays nic= ely with immutability. This style is less-common in popular PHP framewor= ks like Symfony and Laravel, which tend to favor more flexible object co= nstruction. -- validate on mutation -- This paradigm is popular in both Symfony and Laravel and favors an activ= e-record-esqe approach. In this paradigm, each mutator (setter) is respo= nsible for ensuring the property remains valid at the point of modificat= ion. The downside is that inter-property constraints require redundant c= hecks that can be difficult to maintain. The nice thing is that they're = easy to enforce. Of course, these can be mixed-and-matched as needed/desired. The downsid= e with the cloning method here is that it really puts "validation on con= struction" on a back foot. Developers will likely have absolutely no way= to perform validation without rewriting their entire class structures a= nd will make validation during construction basically impossible for imm= utable objects. =E2=80=94 Rob --ceef4687e23e4f6494b7a58f5f58bd73 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
On Thu, May = 15, 2025, at 22:11, Larry Garfield wrote:
On Thu, May 15, 2025, at 2:56 PM, Rob Landers= wrote:
> On Thu, May 15, 2025, at 17:32, Tim D=C3=BCsterhu= s wrote:
>> Hi
>> 
>&g= t; Am 2025-05-15 14:14, schrieb Rob Landers:
>> > For= example, if you have a Money type, you'd want to be able to ensure = ;
>> > it cannot be negative when updating via `with(= )`. This is super 
>> > important for ensuring c= onstraints are met during the clone.
>> 
= >> That's why the assignments during cloning work exactly like reg= ular 
>> property assignments, observing visibility= and property hooks.
>> 
>> The onl= y tiny difference is that an =E2=80=9Coutsider=E2=80=9D is able to chang= e a 
>> `public(set) readonly` property after a `__= clone()` method ran to 
>> completion and relied on= the property in question not changing on the 
>> c= loned object after it observed its value. This seems not to be 
>> something relevant in practice, because why would the ex= act value of the 
>> property only matter during cl= oning, but not at any other time?
>> 
>= ;> Best regards
>> Tim D=C3=BCsterhus
>&= gt; 
>
> Hey Tim,
>
>> why would the exact value of the 
>> pro= perty only matter during cloning, but not at any other time?
&= gt;
> For example, queueing up patches to store/db to commi= t later; during 
> the clone, it may register various = states to ensure the patches are 
> accurate from that= point. That's just one example, though, and it 
> sug= gests calling __clone *before* setting the values is the right 
> answer.
>
> I think Larry's idea o= f just using hooks for validation is also pretty 
> go= od. As Larry said, the only thing you can really do is throw an 
> exception, and the same would be true in a constructor as w= ell.
>
> =E2=80=94 Rob

The limit of hooks is that they're single-property.  So depending= on how your derived properties are implemented, it may be insufficient.=   I could easily write such an example (the hooks RFC included some= ), but how contrived they are, I don't know.

--= Larry Garfield


Yeah= , the validation won't be too automatable (ie, in a base class) without = at least having reusable hooks. It's important to be mindful that there = are approximately three different paradigms when it comes to validating = objects (and they apply to frameworks differently) in PHP.
-- validate on serialization --

Thi= s paradigm is mostly used in symfony via doctrine/serializer. An object = is allowed to be in an "invalid" state and is usually constructed in a "= zero" state, and then state is applied over the lifetime of the applicat= ion. Only during serialization to the wire is it usually validated. So, = it usually looks something like this:

$user =3D= new User();
$user->name =3D "Rob"
$user->id =3D= 123;

When you receive an object in a funct= ion, you will likely have to validate that specific properties are set b= efore operating on it, otherwise you can end up with bugs. The nice thin= g about this style is that you can build up an object's state over a lon= ger period (such as processing a form input or a database query result).=

-- validate on construction --

<= /div>
This paradigm is commonly used in value objects and more = functional-style PHP. The idea is that an object must be valid by the ti= me it is constructed and does not allow partially formed objects to exis= t. All properties are validated in the constructor, and invalid combinat= ions throw exceptions immediately. This tends to lead to more robust cod= e, particularly when the object represents a meaningful invariant (e.g.,= Money, EmailAddress, Uuid). Here's what it looks like= :

$user =3D new User(name: "Rob", id: 123);

The dowside is that its harder to build objects pi= ece by piece and usually requires factories, DTOs, and builder patterns = for times when not all the data is available upfront. This approach is u= sually seen in functional, DDD (domain driven design), or strict typing = contexts and plays nicely with immutability. This style is less-common i= n popular PHP frameworks like Symfony and Laravel, which tend to favor m= ore flexible object construction.

-- validate o= n mutation --

This paradigm is popular in both = Symfony and Laravel and favors an active-record-esqe approach. In this p= aradigm, each mutator (setter) is responsible for ensuring the property = remains valid at the point of modification. The downside is that inter-p= roperty constraints require redundant checks that can be difficult to ma= intain. The nice thing is that they're easy to enforce.

Of course, these can be mixed-and-matched as needed/desired. Th= e downside with the cloning method here is that it really puts "validati= on on construction" on a back foot. Developers will likely have absolute= ly no way to perform validation without rewriting their entire class str= uctures and will make validation during construction basically impossibl= e for immutable objects.

=E2= =80=94 Rob
--ceef4687e23e4f6494b7a58f5f58bd73--