Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:128416 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 9D3BF1A00BC for ; Thu, 7 Aug 2025 06:46:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1754549109; bh=MPBJLRAtJUQcc5bc1k+pceg9JhatBX3F7qP5HnJ9VPc=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=YXFGqNgnHa2bwLVikOGptd8dMlIdA2A4u7+5VsxOKiCnh6VERiHrNq2xl3EESGyHX vRRE5DZsDzLkMZxc0kFV/voyHvG+myqGDIfVdNKO1SbYhdugHv9Tcd8qy4HDj0A41r 5SNJGVMtOOecHB8njkXUQED+3QEv/EY/qAKT3THqXlO5RRQq+/cMYInbn7dKhYEvSf 1ZqdaJkJfNdl43ojev+U3rKaCCWoX8tWHzkzosIlUUxZbGXNHHTuege997G2UfW17e +jktSSUw8JMxEhvA/6NLvXnBwpGlzc/5itZrd2SpuOsVbPX54BmUdMjWRHPROpPO3g EJAVEo50w/1DA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 97D72180048 for ; Thu, 7 Aug 2025 06:45:08 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.4 required=5.0 tests=BAYES_05,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.1 X-Spam-Virus: No X-Envelope-From: Received: from fhigh-b2-smtp.messagingengine.com (fhigh-b2-smtp.messagingengine.com [202.12.124.153]) (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 ; Thu, 7 Aug 2025 06:45:08 +0000 (UTC) Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfhigh.stl.internal (Postfix) with ESMTP id C73787A00D9; Thu, 7 Aug 2025 02:46:46 -0400 (EDT) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-05.internal (MEProxy); Thu, 07 Aug 2025 02:46:46 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bottled.codes; h=cc: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=1754549206; x= 1754635606; bh=b5EFEd1NMFrbpLG+XIomRmLQFy1H7prF5ksUzp8ngIw=; b=Z Qj5aNdaKssphopJRRaQkjATJwx0berJOUMHK+Zsav1wsJnnhxmakrMsGxCIWHp6w y9GKRaB1C0EdI5PBQscIRisv9kBLX7zWV2eG5eTz3squwrTkEk/mVWMnBOCZIeDr LtDITbFVVhOBGUd1nyJUndng8qza77lknc+qi30uwj2k12mLvh1o1ijLNVGxSaPm 1OOzhdVvH/Phy/zTu+BLzwFgZJwEUDuEVlQkA4loCs4H82TYx0vdCQ+Qppu1E6B/ fss6H3/rf+tfOQZRd1U9hth1EyM/sZ+AqncmRWqMVIzOC9ZrbLzp6ZPx//DC5alf uI/5uAFeNL9uFSWIVtgHw== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc: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= 1754549206; x=1754635606; bh=b5EFEd1NMFrbpLG+XIomRmLQFy1H7prF5ks Uzp8ngIw=; b=JocXWueTlhLDnzZCjsqh4zbSgCYGi+ThbQYMcKOUEmNRUSRNIU+ HrAYBPppMU11IsNvL2hEWRvuH1A3372mbVBuJsjTjmTrmgj1WDXGh55/Hwtdqyc+ KwEaYRDgZAHWXECMDSxliQRMrz/6inUOANx+1w2OZEVjG3gOeFJ2Oatov+3rGkdb jwpzPGiUF3ZD3MPShamQNT7QYoH2btURJ+P5BcyhbMtYNYvaFuGK12woXRy2P2wd S5wLfi/yYwH097ygw8SRU8YGmuQX3C82U/4fDZEc8xzBrHphm1DAgjWkH2sC5iRZ D69ExAlixCllezuVgNGLTo/5xPhvSfoVhhA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdduvddtvdehucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepofggfffhvfevkfgjfhfutgesrgdtreerredtjeenucfhrhhomhepfdftohgsucfn rghnuggvrhhsfdcuoehrohgssegsohhtthhlvggurdgtohguvghsqeenucggtffrrghtth gvrhhnpeeiueethedvvdefjefhgfeiheelheehtdfhfeekjefflefgvedvkeduteejjedt tdenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehroh gssegsohhtthhlvggurdgtohguvghspdhnsggprhgtphhtthhopedvpdhmohguvgepshhm thhpohhuthdprhgtphhtthhopehinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvg htpdhrtghpthhtohephhgrnhhskhhrvghnthgvlheshigrhhhoohdruggv X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id 575E91820074; Thu, 7 Aug 2025 02:46:46 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface Precedence: list list-help: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 X-ThreadId: ApgyNlIcRpMw Date: Thu, 07 Aug 2025 08:46:26 +0200 To: "Hans Krentel" Cc: internals@lists.php.net Message-ID: In-Reply-To: <1754480697189.440122623.4156562731@yahoo.de> References: <1754480697189.440122623.4156562731@yahoo.de> Subject: Re: [PHP-DEV] Protected inheritance hierarchies Content-Type: multipart/alternative; boundary=430ba8837cce4b93a551d1f69a7c85de From: rob@bottled.codes ("Rob Landers") --430ba8837cce4b93a551d1f69a7c85de Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Thu, Aug 7, 2025, at 00:38, Hans Krentel wrote: >=20 >=20 >=20 > On Wednesday 06 August 2025 13:41:14 (+02:00), Rob Landers wrote: >=20 > >=20 > >=20 > > On Wed, Aug 6, 2025, at 13:26, Hans Krentel wrote: > > >=20 > > >=20 > > >=20 > > > On Sunday 03 August 2025 11:30:13 (+02:00), Rob Landers wrote: > > >=20 > > > > I'm not sure that this is a bug. You can redeclare the same type= and=20 > add=20 > > > hooks (or change them), which breaks all assumptions about=20 > > > substitutability. > > >=20 > > > Rob, maybe you can lecture me a bit: Isn't substitutability on the=20 > public=20 > > > interface / protocol only? What am I not seeing in your example? > >=20 > > From a child class's perspective, the "public interface" is both=20 > protected + public of the parent. If you change or misuse a parent's=20 > implementation or invariants, it violates LSP, even if it doesn't affe= ct=20 > external clients immediately. >=20 > Ah okay, that part is not in my book, this explains to me why in your=20 > example it violates substitutability for you, and with that thinking i= t=20 > also prevents or degrades implementability for me so to say, as otherw= ise I=20 > could not make use of visibility in classes - it would take away that = tool=20 > from me or I would not treat it well, potentially leading to defects i= n the=20 > program. See my reply to Jonathan. But you are free to dismiss LSP when needed. T= here are a lot of times when LSP isn=E2=80=99t the right design constrai= nt (which I briefly mention in that email), for example, during larger m= igration/refactors, specialized proxies, caching results, etc., or even = using sibling classes as friend classes. PHP doesn=E2=80=99t strictly enforce LSP everywhere. It will get out of = your way when you need it to. It=E2=80=99s your code, you can do whateve= r you want with it.=20 Even when I see an LSP violation at work (rare, but it happens), I don=E2= =80=99t point it out as such, but instead point out why the approach is = a bad idea (maintainability, principle of least surprise, etc). If they = do it continuously, then I might have to invest in some coaching for the= dev, but mostly, people don=E2=80=99t violate LSP for the more obvious = reasons, and when they do, they usually have good reasons (see above). >=20 > > > > Take for example: > >=20 > > class Fruit { > > public string $kind { get =3D> "fruit" } > > } > >=20 > > class Vegetable extends Fruit { > > public string $kind { get =3D> "vegetable" } > > } > >=20 > > function foo(Fruit $fruit) {} > >=20 > > foo(new Vegetable); // hmmm > >=20 > > This is a "soft" violation that only makes sense to us humans, but P= HP=20 > allows it. It requires us humans to realize we are performing an LSP=20 > violation and refactor the code so that we don't pass a Carrot to some= one=20 > expecting a Mango. >=20 > Thankfully in this example it is all public, but I definitely would sa= y=20 > this is not an LSP violation, just saying. >=20 > > > > This can be done through protected means as well (simply replace the=20 > properties above as protected properties used internally), and it won'= t be=20 > as obvious to consumers outside the class, but still there, nonetheles= s. > >=20 >=20 > Okay, this is it probably just like above (for me): When $kind would b= e=20 > protected, it would not be part of the public protocol, and the=20 > substitutability test with the PHP runtime would still pass for the=20 > foo(Fruit) event with a Vegetable that is a Fruit (extends). That woul= d be=20 > a test for substitutability, per the PHP runtime guarantees (it return= s=20 > successfully after sending the message), it does not break the program: >=20 > >> an object (such as a class) may be replaced by a sub-object (such a= s a=20 > class that extends the first class) without breaking the program. (WP = LSP)=20 > << >=20 > Still trying to learn more, though. >=20 > Let me guess: The following hierarchy is not substitutable for you, as= we=20 > can still pass Vegetable for Fruit on foo()'s protocol. Is that correc= t? >=20 >=20 > class Fruit { > // intentionally left blank > } >=20 > class Vegetable extends Fruit { > // intentionally left blank > } >=20 > function foo(Fruit $fruit) {} >=20 > foo(new Vegetable); // hmmm >=20 >=20 > -- hakre I don=E2=80=99t see any reason why this example would violate LSP. There= is no discernible difference between the two classes. LSP only says the= y are substituable in regards to type, and behaviour, and an empty class= is probably only a sentinel value, in which case the behaviour is exter= nal to the type. I might have an issue with saying a vegetable is a frui= t, but that is a naming issue=E2=80=A6 and naming is hard.=20 =E2=80=94 Rob --430ba8837cce4b93a551d1f69a7c85de Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable


On Thu, Aug 7, 2025, at 00:38, Hans Krentel wrote:


On Wednesday 06 August 2025 13:41:14 (+02:00)= , Rob Landers wrote:

>&= nbsp;
> On Wed, Aug 6, 2025, at 13:26, Hans Krentel wrote:<= /div>
> > 
> > 
> >&= nbsp;
> > On Sunday 03 August 2025 11:30:13 (+02:00), Ro= b Landers wrote:
> > 
> > > I'm = not sure that this is a bug. You can redeclare the same type and 
add 
> > hooks (or change them), which bre= aks all assumptions about 
> > substitutability.
> > 
> > Rob, maybe you can lecture m= e a bit: Isn't substitutability on the 
public 
> > interface / protocol only? What am I not seeing in your = example?
> From a child class's perspe= ctive, the "public interface" is both 
protected + public= of the parent. If you change or misuse a parent's 
imple= mentation or invariants, it violates LSP, even if it doesn't affect = ;
external clients immediately.

Ah ok= ay, that part is not in my book, this explains to me why in your 
example it violates substitutability for you, and with that thi= nking it 
also prevents or degrades implementability for = me so to say, as otherwise I 
could not make use of visib= ility in classes - it would take away that tool 
from me = or I would not treat it well, potentially leading to defects in the = ;
program.

See my reply = to Jonathan. But you are free to dismiss LSP when needed. There are a lo= t of times when LSP isn=E2=80=99t the right design constraint (which I b= riefly mention in that email), for example, during larger migration/refa= ctors, specialized proxies, caching results, etc., or even using sibling= classes as friend classes.

PHP doesn=E2=80=99t= strictly enforce LSP everywhere. It will get out of your way when you n= eed it to. It=E2=80=99s your code, you can do whatever you want with it.=  

Even when I see an LSP violation at work= (rare, but it happens), I don=E2=80=99t point it out as such, but inste= ad point out why the approach is a bad idea (maintainability, principle = of least surprise, etc). If they do it continuously, then I might have t= o invest in some coaching for the dev, but mostly, people don=E2=80=99t = violate LSP for the more obvious reasons, and when they do, they usually= have good reasons (see above).


>
> Take = for example:
> class Fruit {
>   public string $kind { get =3D> "fruit" }
= > }
> class Vegetable extends Fruit= {
>   public string $kind { get =3D> "vegetab= le" }
> }
> function foo(= Fruit $fruit) {}
> foo(new Vegetable);= // hmmm
> This is a "soft" violation = that only makes sense to us humans, but PHP 
allows it. I= t requires us humans to realize we are performing an LSP 
violation and refactor the code so that we don't pass a Carrot to someo= ne 
expecting a Mango.

Thankfull= y in this example it is all public, but I definitely would say 
this is not an LSP violation, just saying.

>
> This can be done through protected means as well = (simply replace the 
properties above as protected proper= ties used internally), and it won't be 
as obvious to con= sumers outside the class, but still there, nonetheless.
>&n= bsp;

Okay, this is it probably just like above = (for me): When $kind would be 
protected, it would not be= part of the public protocol, and the 
substitutability t= est with the PHP runtime would still pass for the 
foo(Fr= uit) event with a Vegetable that is a Fruit (extends). That would be&nbs= p;
a test for substitutability, per the PHP runtime guarantees= (it returns 
successfully after sending the message), it= does not break the program:

>> an object= (such as a class) may be replaced by a sub-object (such as a 
class that extends the first class) without breaking the program. = (WP LSP) 
<<

Still trying = to learn more, though.

Let me guess: The follow= ing hierarchy is not substitutable for you, as we 
can st= ill pass Vegetable for Fruit on foo()'s protocol. Is that correct?
=


     class Fruit = {
         // intentio= nally left blank
     }

     class Vegetable extends Fruit {
         // intentionally left= blank
     }

&nb= sp;    function foo(Fruit $fruit) {}

=
     foo(new Vegetable); // hmmm

=

-- hakre

=
I don=E2=80=99t see any reason why this example would violate LSP. = There is no discernible difference between the two classes. LSP only say= s they are substituable in regards to type, and behaviour, and an empty = class is probably only a sentinel value, in which case the behaviour is = external to the type. I might have an issue with saying a vegetable is a= fruit, but that is a naming issue=E2=80=A6 and naming is hard. 

=E2=80=94 Rob
--430ba8837cce4b93a551d1f69a7c85de--