Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119586 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 38255 invoked from network); 21 Feb 2023 12:40:25 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 21 Feb 2023 12:40:25 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 1D3B6180553 for ; Tue, 21 Feb 2023 04:40:25 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-yb1-f174.google.com (mail-yb1-f174.google.com [209.85.219.174]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 21 Feb 2023 04:40:24 -0800 (PST) Received: by mail-yb1-f174.google.com with SMTP id cf8so4251855ybb.11 for ; Tue, 21 Feb 2023 04:40:24 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=o+Hg/GELL5HeWst7OOJCxIZsgD67II030Y+OsjBe4LM=; b=I5SNikgK0Ik2HqIvn5pIERZenciCsHrtbUhlBTIHw5xup8jEiRqlVnu4ZWJ2i5x+Cy E5x7ZUD1IOxxUnkAUAuNnEj80px+7DC0Y6FIvLHp53/Z/ijrh4CSsmI/RWbscUKabpZe uDg29Zhwq5uXHqy+dpWf2hINLaruaK8WpZ3Jh81wgc3+S8OQiVMYLUJzk4hy+dmS4AVG lJ3CDC2GAuRslPsg01dnT4oNh3FuIDS3QaxdlvUTRVLVCSkAvQaJgaybCEcPu7GTBwzC kkHq4rphufVq+N2iq2Wd0aKWEkX/d+GLmryCOc0r6ZgXk8C34vO90LHF4FwG8QCEAtVy hgdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=o+Hg/GELL5HeWst7OOJCxIZsgD67II030Y+OsjBe4LM=; b=1GldwumVrRZgYnlBYwttBliL16uRYZptORniAfFlEh0IwwrF/tEWLI54Me+prl/bQ6 oUXPPlZVTcdRswejdD93rg6HDDmZZmOSd1nKWgUq7otPQl9kQC+NwdYjXGfX58etQAkX B8dE3s/Y2rFcr3kb9pWMWr9+eHPbgaSEUew+5pahughSgizttU/bRbx6Jb6COZqdH0eE +lktrZIsFAs2XASQ4QqUYap22RLasDnPgRWeXIIBweRqh4L5sJDlftzuPggN+hIeqzdt h/SAUIz1x4WFOXnvfFZGMsQiiGPi4KkiXVD08ia+Zi2OmdvcfAOQSFNmYFzp6uMUUkm1 QWFw== X-Gm-Message-State: AO0yUKUywddjGglgpLFfzNlUfWyDn8IGVtzVePaslKVkZaVDaFVHNWnB ZmZhR3shfuO4W2VZK44owcX0Z/CQmn07J+hoPBU= X-Google-Smtp-Source: AK7set9Bs/uWiw3SvQbkskdrZ2ayb/Tl9GURl+J2+GP1gvuxiaBhi8M/BmFBDMXKjEOgenXDcCa5I1b7PDmTA1F79q8= X-Received: by 2002:a5b:681:0:b0:95f:79e0:c114 with SMTP id j1-20020a5b0681000000b0095f79e0c114mr796801ybq.558.1676983223796; Tue, 21 Feb 2023 04:40:23 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: Date: Tue, 21 Feb 2023 13:40:12 +0100 Message-ID: To: someniatko Cc: php internals Content-Type: text/plain; charset="UTF-8" Subject: Re: [PHP-DEV] Class Re-implementation Mechanism From: landers.robert@gmail.com (Robert Landers) On Tue, Feb 21, 2023 at 12:52 PM someniatko wrote: > > Hi again, internals > > My marathon of some crazy ideas continues :D, with less crazy one this time. > > > ## Idea > > Allow "reimplementing" the non-static public API (that is public > properties and methods, excluding constructor) of a class by other > classes like this: > > ```php > final class interface A { > public string $s; > > public function __construct(string $s) { $this->s = $s; } > > public static function fromInt(int $i): self { return new > self((string) $i); } > > public function foo(): int { return 42; } > } > > final class B implements A { > public string $s = 'hello'; > > public function foo(): int { return 69; } > } > > function usesA(A $param): void {} > > usesA(new B); // this works > ``` > > > ## Explanation > > Consider there is a class like this: > > ```php > final class Service { > public function __construct(private SomeDependency $dependency) {} > // ... > } > > final class SomeDependency { > // ... > } > ``` > > We want to write some tests for the Service class, but we don't want > to use a real SomeDependency instance > during tests. A common approach is to either extract an interface > (JUST to make it testable), or to drop the > `final` keyword and allow extending the class. > > Both approaches have their flaws: > - extracting an interface unnecessarily complicates the system, where > only one "real" implementation of an interface is assumed. > - dropping the `final` keyword allows for the rabbit-hole of > inheritance abuse, like greatly described in this article: > https://front-line-php.com/object-oriented > > I believe I came up with a better idea: what if we could leave both > benefits of prohibiting the inheritance abuse and also allow not to > clutter our namespace with excess entities like interfaces? I hereby > suggest to combine the responsibilities of a class and an interface > into one thing like that: > > ```php > final class interface C {} > final class D implements C {} > ``` > > Now other classes can "implement" this class as well. Introduction of > the new syntax (`class interface`) also solves BC problem - if you > want to forbid your classes to be reimplemented whatsoever, you can > still stick to the `final class` syntax. Although it is also possible > to allow "reimplementing" ANY class, then new syntax is not needed - > but some library writers like Marco Pivetta could be sad about that I > suppose. > > Soo..., what do you think? Could this be a valuable addition to the language? > > Regards, > Illia / someniatko > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > This reminds me a lot of C#'s "extension methods" which are quite useful. If PHP had something like that, you could do some really nice things: class BMock { public static function bar from A(): int { return 69; } } $a = new A(123); echo $a->bar(); // output: 69 class BReal { public static function bar from A(): int { return $self->foo(); } } // error A::bar() already defined on BMock where `from A` is syntax sugar for `public function bar(A $self) {}` and trying `$a->bar()` is simply syntax sugar for `BMock::bar($a);`