Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:118402 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 78407 invoked from network); 10 Aug 2022 15:51:21 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 10 Aug 2022 15:51:21 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id D00B01804AF for ; Wed, 10 Aug 2022 10:53:10 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_ENVFROM_END_DIGIT, FREEMAIL_FROM,FREEMAIL_REPLYTO_END_DIGIT,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,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-pj1-f54.google.com (mail-pj1-f54.google.com [209.85.216.54]) (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 ; Wed, 10 Aug 2022 10:53:10 -0700 (PDT) Received: by mail-pj1-f54.google.com with SMTP id o3-20020a17090a0a0300b001f7649cd317so2962625pjo.0 for ; Wed, 10 Aug 2022 10:53:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:reply-to:in-reply-to:references :mime-version:from:to:cc; bh=+WAzkIvzYQhWtczPA/46yRDg7CEnoCa7Txd9tf/bKxM=; b=H2PuAFj1GkH0bV+vHwgi8+2BG7s1OTxrd32YyxrVIaYgbUYln0hNJ6B4WSzmZJbni3 gCCd17ZU/cLWcCTk0iUh9ant+uaoSz1SFSkDxoDv06ize/AL5GXriXHW106Ml0haO2YJ thEV7xiyjxCunD+TiL/4T2p5+mMFVBD5kfXQtg6RHSSA9HyCqfgA0hG12aHXKCppZ0Ft M+ObR5LGQTxFS8ELvgCfAmHJJv/gy0Wyjao1fVTLLk3q9SQiC0E2F2Hqeke8tnkYFwHJ sQHIwLbwArl9MpVxjcJo7jwakOnZQ35MirHtmQ04Ag2HsXEnlnn5DLV8EUlQ5pBp2T7c N26Q== 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:reply-to:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc; bh=+WAzkIvzYQhWtczPA/46yRDg7CEnoCa7Txd9tf/bKxM=; b=KSxYvRBlCNvL9FM8MF2AHI7ne0MuGygpPNrVa+iR1eKfnJceaSyc+VqPwmXhgweb/7 RBsjpetdFCwd8LKwDhMzIN8tmTCw1Td6VZHE7mvRsVIy7GDvOl53Okq7eWKQ14CAW2wf G0ERBH4HZZYu6cAo+c599bvfq1AtTeDhUBtEgf0egJ7u3PQvArbccBDiaXSvFz3oelPW LvNCsrgHmsJ7edJ5/TvNQTHCVk8K29HvoDgJxyhIZPJelD6nlNqPqrFxuL8U/GVcbU3L A+JKc4IgXypK8j0BXqCpTzNfUUagol1uxrMHmvAtpZfVswCLxUnfp/wzYGYvpIU0R8ZN RBfQ== X-Gm-Message-State: ACgBeo2HXhizrxIK22mA0I5hRz7oebXYXEcx94lvK2cYsKQCAtWuGyTO r+KjEioOSlIRlkDxbQM88/IdNsu67VfLq6Nwk9CiLYZpNkBEcY9m X-Google-Smtp-Source: AA6agR4ic/YIpLnW0nOKjIPYt857G3IYLjAT7at86fsxbR2IMqWafPD6raVIQhvu5ahnmBRUEYQZEVGcGIMHhP7UhNs= X-Received: by 2002:a17:902:7d86:b0:170:a752:cbd1 with SMTP id a6-20020a1709027d8600b00170a752cbd1mr15181985plm.17.1660153989249; Wed, 10 Aug 2022 10:53:09 -0700 (PDT) MIME-Version: 1.0 References: <62f3da67.810a0220.ed5e8.1b2cSMTPIN_ADDED_MISSING@mx.google.com> In-Reply-To: Reply-To: autaut03@gmail.com Date: Wed, 10 Aug 2022 20:52:58 +0300 Message-ID: To: Rowan Tommins Cc: Ben Ramsey , internals@lists.php.net Content-Type: multipart/alternative; boundary="000000000000cd3f1205e5e6b8e2" Subject: Re: [PHP-DEV] Re: [Concept] Extension methods From: autaut03@gmail.com (Alex Wells) --000000000000cd3f1205e5e6b8e2 Content-Type: text/plain; charset="UTF-8" Thanks for explaining it better than I did. Regarding the implementation, that was roughly what I was thinking. But can't we put extension methods second, after real methods but before __call? As far as I understand, the reason to put it after __call is to avoid a performance penalty on __call calls, but this would mean extension methods are not possible for classes that implement __call. Not a huge deal, but a thing to consider. On Wed, Aug 10, 2022 at 8:32 PM Rowan Tommins wrote: > On Wed, 10 Aug 2022 at 17:18, Ben Ramsey wrote: > > > I believe this is also called "monkey patching" in some places, and > > Ruby, Python, and JavaScript all offer some form of object extension > > similar to this. > > > > There is also the PHP runkit extension that provides some of the > > functionality you've described: https://www.php.net/runkit7 > > > > > Monkey-patching generally refers to the ability to completely "re-open" a > class, and implement additional behaviour (or even change existing > behaviour) *with the same privileges as the original definition*. > > Extension methods are a much more constrained feature - they don't break > the class's encapsulation, only provide an extra syntax for operations that > would already be legal. In C#, for instance, calling > "foo.someExtensionMethod(bar)" is just syntactic sugar for the static > method call "SomeClass.someExtensionMethod(foo, bar)", and cannot hide or > over-ride a real method with the same name. > > The challenge in PHP is that so little is resolved at compile-time. > Adapting the example from the first post: > > namespace App\Business; > use extension App\CollectionExtension::map on Collection; > > function foo($x) { > $x > ->map(fn ($value) => $value + 1) > ->map(fn ($value) => $value * 2); > } > > PHP doesn't know until run-time: > > * whether App\CollectionExtension actually exists (the compiler does not > have access to an autoloader) > * whether it defines a "map" method, and applies to type Collection, even > if the user has *claimed* that in the "use" statement > * what type $x will be; even with a type constraint of "Collection $x", it > might be a sub-type, changing the answer to the following question > * whether that class already contains a "map" method, or an __call handler > > I think we would have to implement it as a final fall-back for missing > methods, between __call and throwing an error: > > 1. at compile-time, build a list of in-scope extensions methods; note that > these would just be strings at this point, not loaded code > 2. just before throwing a "method not found" error, loop over the list, > autoloading each entry if necessary; possibly at this point, errors would > be raised for naming conflicts and other violations > 3. check each in-scope extension method in turn for an "instanceof" match > against the current object > 4. if one matches, despatch the call > 5. if none matches, throw an error as normal > > Regards, > -- > Rowan Tommins > [IMSoP] > --000000000000cd3f1205e5e6b8e2--