Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:121791 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 12838 invoked from network); 23 Nov 2023 21:30:07 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 23 Nov 2023 21:30:07 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 16C8118003F for ; Thu, 23 Nov 2023 13:30:11 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-3.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-vk1-f182.google.com (mail-vk1-f182.google.com [209.85.221.182]) (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, 23 Nov 2023 13:30:10 -0800 (PST) Received: by mail-vk1-f182.google.com with SMTP id 71dfb90a1353d-4ac0bead615so135564e0c.0 for ; Thu, 23 Nov 2023 13:30:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1700775005; x=1701379805; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=Z/qpdfFUpMPYwarVK6/PfuG1mL008uPmqgHHxQ2vJzQ=; b=gXDgf0y/rva/aZRtPjBV3atpmi0fUcrHdKWA2yLi5L/FM3n0jogDyvChFhGtVK9og6 S62C73N5qdsLU5hEYWz9toFhzS52oO10iv9bwIIrbRPMBk4plSNg0lpSHGF7Dq0p7Q8U /r71DO1pjCvyVJBFfrk7ByfK19rt9V23PrD8gmOZGzRI58DLlcigtHzk4WxIqb7w5QAP gEfY5RiRRS7QiTqy77/mVy2QeKibAcKEeQY+Qd7Is3QlSpWegZEPIpGwyG51OYpFC09h N+/Ij3aZD8VbTlbpM4DzVqS+s3UEdBgSkNEJbSenE5nJqPsl9PJoIowH2oNq15KHOgK1 6w6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700775005; x=1701379805; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=Z/qpdfFUpMPYwarVK6/PfuG1mL008uPmqgHHxQ2vJzQ=; b=mlm1ubKwjfLhe3XFrCmDtxz9UNiD+tCQwpjLr6Gfo3yYwwsxQxRg3eyfb7mFeUjo9v C/hRqCnFT7UVXSVtd2kE+kscYKrlpooOcOyoxUSnL6QerEI8EL2UNIBqHBCuxnjFxxSH SJTckgoQcDzPJ2hAeaNK+yRb2XHBvTXYJjvMHlhF0MnmDGc10FRooXuJq7gRMKmWydnY kBzid0nfaDBIciqwnLAXUdr3Yzsi551hJ58pxvgrykGm7IWvGlRB27Rb0zNyABxvGRsT jHuXW9ygHNnpvoyL86ATH+1IfT5D7+6Rstazn5aFc2pcJDjWoAyESWdGKYrPKnnQNN+Y MO8w== X-Gm-Message-State: AOJu0YyXgiYxymPGG8Nl007UdQhAE1gKDxTQ2HL4plinngxeDE598F08 F3K48OnPBpEBmfEi/a5IYu9i9Rc4VX5qw8MLdZjx7kRf X-Google-Smtp-Source: AGHT+IHiVfatAANdydJEKTXrVuPwAXzXW3c96OG8i8Y22rF5TUqgg24ZGoTfj2GETDBF7q4mt2o2cYLRi2crM4FAXKs= X-Received: by 2002:a05:6122:4b08:b0:4ac:35ec:df6a with SMTP id fc8-20020a0561224b0800b004ac35ecdf6amr544210vkb.1.1700775005256; Thu, 23 Nov 2023 13:30:05 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: Date: Thu, 23 Nov 2023 18:29:29 -0300 Message-ID: To: Robert Landers Cc: internals Content-Type: multipart/alternative; boundary="0000000000000800bf060ad88a7a" Subject: Re: [PHP-DEV] [RFC][Discussion] Why can constructors violate LSP? From: deleugyn@gmail.com (Deleu) --0000000000000800bf060ad88a7a Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, Nov 23, 2023 at 5:31=E2=80=AFPM Robert Landers wrote: > Hello Internals, > > As you may know, an inherited method cannot reduce the visibility of > an overridden method. For example, this results in a fatal error > during compilation: > > class P { > public function hello($name =3D 'world') { > echo "hello $name\n"; > } > } > > class C extends P { > private function hello($name =3D 'world') { > parent::hello($name); > echo "goodbye $name\n"; > } > } > > However, we can make certain methods private anyway, namely, > constructors (I haven't gone hunting for other built-in methods yet). > This is perfectly allowed: > > class P { > public function __construct($name =3D 'waldo') { > echo "hello $name\n"; > } > } > > class C extends P { > private function __construct($name =3D 'world') { > parent::__construct($name); > echo "goodbye $name\n"; > } > } > > To my somewhat trained eye, this appears to violate the Liskov > Substitution Principle, for example, this now can have hidden errors: > > function create(P $class) { > return new (get_class($class))(); > } > > proven by: > > $c =3D (new ReflectionClass(C::class)) > ->newInstanceWithoutConstructor(); > > create($c); > > Even though we thought we knew that the constructor was declared public. > > I'd like to propose an RFC to enforce the covariance of constructors > (just like is done for other methods), to take effect in PHP 9, with a > deprecation notice in 8.3.x. > > I'm more than happy to implement it. > > Does anyone feel strongly about this one way or the other? > Constructors are an implementation detail of a specialized class and as such they're not subject to LSP because the goal of LSP is to be able to make sure that any object of a given type hierarchy can be used to accomplish a certain behavior. If you take a step back from PHP's dynamic nature and think about LSP from a more pure type system, the fact you're expecting an object of type C, but then you completely disregard everything about the object itself and dive into it's metadata to build another object, that's the moment you're no longer playing by the rules of OOP. It's like those mathematical equations that prove that 1 =3D 2, they a= ll have one thing in common: they end up dividing by 0 at some point. OOP here dictates that you should reach for patterns like Builder, Abstract Factory or similar. That way you constraint yourself to the rules of OOP and you won't get weird outcomes. From another point of view, when a type is expected by a function or method, all we can expect from it is whatever was defined as the blueprint (class/interface) of that object and the __construct() is a special method that is not assumed to be part of that blueprint because it's not reasonable to do `$object->__construct();` after receiving an object. As such, a constructor cannot break LSP because the constructor is not part of the object's API from a "receptor" point of view. I don't have a vote so take my opinion with a bucket of salt, but if I could I would definitely vote against such RFC. --=20 Marco Deleu --0000000000000800bf060ad88a7a--