Re: [RFC][Discussion] Why can constructors violate LSP?
| From: | Rowan Tommins | Date: | Thu, 23 Nov 2023 21:27:00 +0000 |
| Subject: | Re: [RFC][Discussion] Why can constructors violate LSP? | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-121790@lists.php.net to get a copy of this message | ||
On 23 November 2023 20:31:09 GMT, Robert Landers <landers.robert@gmail.com> wrote:
>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.
There's a lot more than visibility that is enforced on normal methods, but isn't on
constructors. For instance this is also valid:
class A {
public function __construct(int $foo) {}
}
class B extends A {
public function __construct(string $bar) {}
}
From a theoretical perspective, I think the argument is roughly that classes aren't first-class
citizens that you can pass around, so substitutability doesn't apply. You can't for
instance write a function that explicitly depends on "a class definition inheriting from
A", like this:
function foo(class<A> $class) {
$instance = new $class(42);
}
You can certainly simulate such code with some strings and maybe a bit of reflection, but the
language isn't going to make any guarantees about it.
I did just think of a counter-example, though, which is that "new static($param)" is
allowed, even though there's no way to know if $param will be accepted by subclasses. Maybe it
shouldn't be allowed?
From a practical point of view, it's often very useful to sub-class something and provide a
constructor with a different signature. Maybe your subclass has additional dependencies; maybe it
can hard-code or calculate some of the inputs to the parent constructor for a special case, etc.
A private constructor can be used in conjunction with static methods to simulate multiple named
constructors (createFromString, createFromRequest, etc). Given the lack of other guarantees,
there's no particular gain in preventing that just because the parent class has a public
constructor.
Regards,
--
Rowan Tommins
[IMSoP]