Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:128425 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 0EDBC1A00BC for ; Thu, 7 Aug 2025 22:02:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1754604031; bh=+b4rRpxswyeO901Br5Kh4t0Lo4qjvEVFi62ceVJx9XY=; h=Date:From:To:Cc:In-Reply-To:References:Subject:From; b=NtoWIDvWV+ViusQvZLafOwG1Yej6IDy8YB4oZv6z3hz6nhxMy3EvV3/QPrJjNdnTc D3wwdZsTkMb5LpMcZ9eHt2nLgpfX3J7qFOe0It96U9BggRO6C3mi86x7ZX0Wk61FOm aJ1MWzrcrfmlLg6h2firqiHhITuKx38s319crQ+3b0Rr8rVug1+TmxJ6EiLwbVyW5K t2GOsjRnt8Il/CV8CNwP63Z5Q04ZPlYXp6NzcFmz6VuH/B0HcOw+mhDcKsmU35muUX spec1e+k9ReRuB0t8a0Z5tq72RzKnl01ILSi6yvxyV5mmw4nv3JfHtaiepp/YjJsIk yv9He4rfQwW9A== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 5B49D18005C for ; Thu, 7 Aug 2025 22:00:30 +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=-2.8 required=5.0 tests=BAYES_00,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 fout-b7-smtp.messagingengine.com (fout-b7-smtp.messagingengine.com [202.12.124.150]) (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 22:00:19 +0000 (UTC) Received: from phl-compute-05.internal (phl-compute-05.internal [10.202.2.45]) by mailfout.stl.internal (Postfix) with ESMTP id 755E11D0000A; Thu, 7 Aug 2025 18:01:58 -0400 (EDT) Received: from phl-imap-05 ([10.202.2.95]) by phl-compute-05.internal (MEProxy); Thu, 07 Aug 2025 18:01:58 -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=1754604118; x= 1754690518; bh=JvIt2LaVqCgbXZVexGM/UkKC7I+my2mGTQAS643Pxz0=; b=c Bnwcp7LYY+x7WtxKBrkzPe1YxvfrCsTM369Fg75tsUHU6mcvjmLE+YjoDVGSzlOu 6/vpDv+8jf40G5NbamIFsWCVToy4NA3kJCF5duqdOFvh69LOIHFuLXtA6NzZm5PN uIWrdByY5NTr2wISqdG3wPkSEhijMdgUmlMxQOyXjelCRvgmdM6vrr0MUxK+i9su poqr/IxQ+36aldBcBKY/6HrwpwhuOhJONbwsrPP8kPDjN/gXG2Bkq2NDtJgxMtdq Ih0fTxffXhhKlrXxs8nHBda3XouAjkRHGRNIBAllY7AVMstfDVJuXco1Aot9JzRO lY3bG3Zb4/IirsDVkPsnA== 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= 1754604118; x=1754690518; bh=JvIt2LaVqCgbXZVexGM/UkKC7I+my2mGTQA S643Pxz0=; b=VDPziK9VeaGeiYoJGYeXhZ0+2PF2+WP8a3gNhdF6Rk6K97Er+4q fRQeKuLxAXTPVJAqfaZNPPAGvV0dbx9uB0MPVcfOj9IswVCqiqAGK1r4l0vdDJIe s198CHlabOLio10GZX5whWFmoLBNH7HBHpkOaFoVFWIhuRTfcfJPTWIJUUgHokYM ITQP/E04uIkiz9HowX7qCIEHmnRDgF69yTGYCiVs/QAESZvAPXeidiVIwHVgSLwS jnnx77+onfE0uYEQMRakt0yAxCQSAUcJqBjgVHlr3VMZOzDE476ft1Lk2CUSvQ9d VTWYu6/queLucTUggky6xUSpBdRD2vjytJA== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeeffedrtdefgdduvddvtdekucetufdoteggodetrf dotffvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfurfetoffkrfgpnffqhgenuceu rghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnecujf gurhepofggfffhvfevkfgjfhfutgesrgdtreerredtjeenucfhrhhomhepfdftohgsucfn rghnuggvrhhsfdcuoehrohgssegsohhtthhlvggurdgtohguvghsqeenucggtffrrghtth gvrhhnpeeiueethedvvdefjefhgfeiheelheehtdfhfeekjefflefgvedvkeduteejjedt tdenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehroh gssegsohhtthhlvggurdgtohguvghspdhnsggprhgtphhtthhopeefpdhmohguvgepshhm thhpohhuthdprhgtphhtthhopehjnhhvsehjnhhvshhorhdrnhgvthdprhgtphhtthhope hinhhtvghrnhgrlhhssehlihhsthhsrdhphhhprdhnvghtpdhrtghpthhtohephhgrnhhs khhrvghnthgvlheshigrhhhoohdruggv X-ME-Proxy: Feedback-ID: ifab94697:Fastmail Received: by mailuser.phl.internal (Postfix, from userid 501) id C50AC1820074; Thu, 7 Aug 2025 18:01:57 -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: Fri, 08 Aug 2025 00:01:37 +0200 To: "Jonathan Vollebregt" , "Hans Krentel" Cc: internals@lists.php.net Message-ID: <387eee1d-c46f-460d-965e-c0500255ee57@app.fastmail.com> In-Reply-To: References: <1754480697189.440122623.4156562731@yahoo.de> Subject: Re: [PHP-DEV] Protected inheritance hierarchies Content-Type: multipart/alternative; boundary=a936b2c716334495b38052f9a6719906 From: rob@bottled.codes ("Rob Landers") --a936b2c716334495b38052f9a6719906 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On Thu, Aug 7, 2025, at 20:37, Jonathan Vollebregt wrote: > On 8/7/25 12:38 AM, Hans Krentel wrote: > > > > From a child class's perspective, the "public interface" is bot= h=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 af= fect=20 > > external clients immediately. > >=20 > > Ah okay, that part is not in my book, this explains to me why in you= r=20 > > example it violates substitutability for you, and with that thinking= it=20 > > also prevents or degrades implementability for me so to say, as=20 > > otherwise I could not make use of visibility in classes - it would t= ake=20 > > away that tool from me or I would not treat it well, potentially lea= ding=20 > > to defects in the program. >=20 > Don't believe everything you read on the internet. >=20 > If you weren't allowed to change a parent's implementation, then you=20 > wouldn't be permitted to override methods at all, at which point=20 > inheritance is pointless. >=20 > It's funny that he's starting to talk about invariants here. Seems he=20 > doesn't realize every example he's given so far is covariant (Besides=20 > the one at the beginning of the thread where he confused static and=20 > non-static properties) >=20 > He's trying to argue that LSP is about implementation when it's not.=20 > This is an interface with a function signature: >=20 > interface I { > function f(): string; > } >=20 > See a fruit anywhere? Me neither. That's because there isn't one. It's=20 > not part of the signature. It's not part of the interface. It's not pa= rt=20 > of the definition. It's not part of the contract. >=20 > This is a class with _the same function signature_: >=20 > class C { > function f(): string { > return "fruit"; > } > } >=20 > In fact, this class could implement that interface without any problem= s,=20 > because the signature is identical. The types are identical. There is = no=20 > LSP violation. There is also no contract that implies C::f() returns=20 > "fruit". >=20 > If you made that assumption I'd call it a lack of error handling from=20 > someone who only considered the happy path. Static analysis tools exis= t=20 > to stop you from making these mistakes. >=20 > Once more, just to drive the point home. This is an interface with a=20 > function signature: >=20 > interface I { > public int $p { get; } > } >=20 > This is a class with the same function signature (And one more for goo= d=20 > measure, because I::$p is covariant!): >=20 > class C { > public int $p; > } >=20 > In fact, this class could implement that interface without any problem= s,=20 > because the signature is identical. The types are identical. There is = no=20 > LSP violation. There is no contract that implies that getting C->p wil= l=20 > return a certain value, other than that the value will be an int. >=20 > --- >=20 > Back to the original issue: I'm going to open a github issue on this=20 > since it's clearly a bug and I don't see fixing it breaking any existi= ng=20 > code. >=20 Hey Jonathan: It seems we=E2=80=99re talking past each other a bit, so let me clarify. Liskov=E2=80=99s original work (which is worth reading, since it seems y= ou haven=E2=80=99t) frames LSP as a *behavioural* contract, not merely a= type signature. When the principle was introduced in the 1980s, modern = type systems barely existed=E2=80=94the focus was always on whether subs= tituting a child for a parent would break *expected behaviour*, not just= the surface-level types. For example, if `A::foo(): int` promises to always return a non-zero int= eger, and a subclass overrides `foo()` to only return zero, that violate= s the contract=E2=80=94even though the type signatures match perfectly. = This is the sort of semantic guarantee that LSP is about, and it is disc= ussed in nearly every reputable textbook and conference talk on OO desig= n. Languages like PHP can=E2=80=99t enforce these contracts, but the *pr= inciple* is what helps prevent subtle design bugs and behavioural =E2=80= =9Csurprises.=E2=80=9D You mention that overriding methods is the point of inheritance. Of cour= se! That is where LSP *matters most*. It is about ensuring that overridi= ng methods (and properties) in subclasses don=E2=80=99t break expectatio= ns encoded or implied in the parent. On invariants: These are a textbook part of LSP. The *values* and *guara= ntees* behind properties (not just their types) are what client code may= rely on. That is why invariants are so often referenced in the LSP cont= ext. As for your example with interfaces and signatures: Yes, two signatures = can match perfectly, and yet LSP can still be violated if the contract (= explicit or implicit) is not honoured. Static analysis tools can help, b= ut they only go so far=E2=80=94they can=E2=80=99t check for *semantic* c= ompatibility. So while a language or type system may permit something, that doesn=E2=80= =99t mean it=E2=80=99s a good idea from a design or maintainability pers= pective. Looking forward to your GitHub issue. =E2=80=94 Rob --a936b2c716334495b38052f9a6719906 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable


On Thu, Aug 7, 2025, at 20:37, Jonathan Vollebregt wro= te:
On 8/7/25 1= 2:38 AM, Hans Krentel wrote:
>  > > From a child= class's perspective, the "public interface" is both 
>= ; protected + public of the parent. If you change or misuse a parent's&n= bsp;
> implementation or invariants, it violates LSP, even = if it doesn't affect 
> external clients immediately.<= /div>
> Ah okay, that part is not in my book= , this explains to me why in your 
> example it violat= es substitutability for you, and with that thinking it 
&= gt; also prevents or degrades implementability for me so to say, as = ;
> otherwise I could not make use of visibility in classes= - it would take 
> away that tool from me or I would = not treat it well, potentially leading 
> to defects i= n the program.

Don't believe everything you rea= d on the internet.

If you weren't allowed to ch= ange a parent's implementation, then you 
wouldn't be per= mitted to override methods at all, at which point 
inheri= tance is pointless.

It's funny that he's starti= ng to talk about invariants here. Seems he 
doesn't reali= ze every example he's given so far is covariant (Besides 
the one at the beginning of the thread where he confused static and&nbs= p;
non-static properties)

He's trying= to argue that LSP is about implementation when it's not. 
This is an interface with a function signature:

interface I {
     function f(): string= ;
}

See a fruit anywhere? Me neither.= That's because there isn't one. It's 
not part of the si= gnature. It's not part of the interface. It's not part 
o= f the definition. It's not part of the contract.

This is a class with _the same function signature_:

class C {
     function f(): string= {
         return "fr= uit";
     }
}

In fact, this class could implement that interface without any p= roblems, 
because the signature is identical. The types a= re identical. There is no 
LSP violation. There is also n= o contract that implies C::f() returns 
"fruit".

If you made that assumption I'd call it a lack of error= handling from 
someone who only considered the happy pat= h. Static analysis tools exist 
to stop you from making t= hese mistakes.

Once more, just to drive the poi= nt home. This is an interface with a 
function signature:=

interface I {
   &nbs= p; public int $p { get; }
}

This is a= class with the same function signature (And one more for good 
measure, because I::$p is covariant!):

c= lass C {
     public int $p;
}

In fact, this class could implement that interfa= ce without any problems, 
because the signature is identi= cal. The types are identical. There is no 
LSP violation.= There is no contract that implies that getting C->p will 
=
return a certain value, other than that the value will be an int.

---

Back to the origina= l issue: I'm going to open a github issue on this 
since = it's clearly a bug and I don't see fixing it breaking any existing =
code.


He= y Jonathan:

It seems we=E2=80=99re talking past= each other a bit, so let me clarify.

Liskov=E2= =80=99s original work (which is worth reading, since it seems you haven=E2= =80=99t) frames LSP as a behavioural contract, not merely a type = signature. When the principle was introduced in the 1980s, modern type s= ystems barely existed=E2=80=94the focus was always on whether substituti= ng a child for a parent would break expected behaviour, not just = the surface-level types.

For example, if A::foo(): int p= romises to always return a non-zero integer, and a subclass overrides foo() to only r= eturn zero, that violates the contract=E2=80=94even though the type sign= atures match perfectly. This is the sort of semantic guarantee that LSP = is about, and it is discussed in nearly every reputable textbook and con= ference talk on OO design. Languages like PHP can=E2=80=99t enforce thes= e contracts, but the principle is what helps prevent subtle desig= n bugs and behavioural =E2=80=9Csurprises.=E2=80=9D

=
You mention that overriding methods is the point of inheritance. Of= course! That is where LSP matters most. It is about ensuring tha= t overriding methods (and properties) in subclasses don=E2=80=99t break = expectations encoded or implied in the parent.

= On invariants: These are a textbook part of LSP. The values and <= i>guarantees behind properties (not just their types) are what clien= t code may rely on. That is why invariants are so often referenced in th= e LSP context.

As for your example with interfa= ces and signatures: Yes, two signatures can match perfectly, and yet LSP= can still be violated if the contract (explicit or implicit) is not hon= oured. Static analysis tools can help, but they only go so far=E2=80=94t= hey can=E2=80=99t check for semantic compatibility.
So while a language or type system may permit something, tha= t doesn=E2=80=99t mean it=E2=80=99s a good idea from a design or maintai= nability perspective.

Looking forward to your G= itHub issue.

=E2=80=94 = Rob
--a936b2c716334495b38052f9a6719906--