Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:130485 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 49B8E1A00BC for ; Mon, 30 Mar 2026 00:32:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1774830763; bh=8S7KZNdb2M1KjkJ528BzTBXvW7xCUadb8Za9ST76ph4=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=RZbv34W1Xbz276av9X6fHWqzS6Sv0b33i5Z/h2Nd+0Ds03ZtQQllPCcyZAv2bhZ8g 41EWAgX+hhPKqIc6fOTj8Z+7cc3nT9lGsyBCy4wTNDJMZ68qTlQzuFkFfmw1Li7ih6 a7T//3ydE7Uwu7w57IAl3kBov8zM4VW/Uos8YOVsapAlQ0cxMwhK0tYLxu4qF7zbS4 l80klMyAP4HxRnAF8fyrU4IT1KF03Atm1Bp+PBbl7UgeDRjeXOViZlaIq0IdtojGEy wsHraEYozqFfoa9RrryCpb6jmUZpP1dv6GNmVuPeHJjfotPU6s05OEEFARiuA/CE4c /oPilTp2KLuoQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 7F1AA180069 for ; Mon, 30 Mar 2026 00:32:42 +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=0.6 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_50, 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.1 X-Spam-Virus: No X-Envelope-From: Received: from mail-yx1-f50.google.com (mail-yx1-f50.google.com [74.125.224.50]) (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 ; Mon, 30 Mar 2026 00:32:42 +0000 (UTC) Received: by mail-yx1-f50.google.com with SMTP id 956f58d0204a3-649278a69c5so4157857d50.3 for ; Sun, 29 Mar 2026 17:32:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1774830756; cv=none; d=google.com; s=arc-20240605; b=FrgbiyZ34q7SzzkJA/7JjufyMoSKY+J32GPq9udNIgYidvqywP+zhfz2VllaJAOUMc gDxUPhVV18Gje0/AtrsQQno7Cm4g1tC/sA3TVvt6QUJ0dv9j3riVg23D6SXhVmGAFeN9 CwZpvm/15XNeQKiOtinEt+zprJhD0Iy7FGTrI6qfgD2s+gQ8NEiP4lOkLKPGHiNivD+w lAaMbIRucPFBV6YkpUvAq2v7JXc08osCR9pDPms0GV7IRugtkRiRO63WSo/Ox7PQ0qsq xW/d7YDTH62eo47eesnMip6h8MWeI4Bj3XWAHi2Bu0J8Bu2iw8a0yAKebgyjOru+LdAm BNrw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:dkim-signature; bh=sXGkw3FQDYmH1QtB7/RcRQC9cH6KDvSEgerED7NJ0w0=; fh=SpNbuKluJHLW6DkTmUcPMTEbUU8OqJH/3FGR1ACCxPk=; b=faURkX7Csf0lACWrdJ5xcNkhf1d2Q608NU8XiSqgbq3Hoc+q/AsA6tAvk/kQ+m/B08 d22wf2Xk76VopLiJmK0qTMjfQ6aX5T2kcf55+2BpdbW75H4KT1Ra66tyPo7xjy2enMNl hOFT8e7gI1+xCOxJ0e2yZk0g02DU7N5NV2qU8jCKwJFiHzjQupyFzReBDvTuCy6TEUqw m0USKBpeNMxqCmH+sBRRdCP/UZeAvtyzf5WSqxTDhw7VLnyvK9tVDVApRaFlPha2gBJn 1I+17oC06cfWbyyU8Ku+ESdoPW6UGOVWLxPxYK4KQwSfHiruZzdZ1hscpfVUkFFKITOS iPgg==; darn=lists.php.net ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1774830756; x=1775435556; 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=sXGkw3FQDYmH1QtB7/RcRQC9cH6KDvSEgerED7NJ0w0=; b=i2HP/BbAjEqhzDvIBdldam1eXKIU0PDs5rzyHJbs5H1WvscBHfDABXlq77HCi+f73e 1YpeR8ENffCGSKJ5UKUS2dML3S6m2BvLDmCNqmGNexxv5BpIQ9uRRlBnCyCMerLN3ke4 Or4/Ar70H8z3vr2Rzh+21Te6HcTu8sa4aHLTM8sg2uRF44SWpE5fnmJ0QEFtwUtUQcIx 8wQZW4oOY2+o2ueOtEusWu8fc6TaiovffQEkoU2C9Pczstw1X2jOoe63R61Fn5T8K9Qf r1/6H+T6IXCaQ20nFzBkHsBrtctg9LTIDcfGxTadWOZk9wyR+IGkv3o8QdEtHm4ir+Rv KhBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1774830756; x=1775435556; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=sXGkw3FQDYmH1QtB7/RcRQC9cH6KDvSEgerED7NJ0w0=; b=QGfQziJmzX4F6NJhf3zV1Ko/QyxZXBgX0VUkfhCUtACr+52CdXSgCTvg/sal2U0owy M+XMPC4dSv+B+aMwagTtwaSsTXWaea2vLTX/CJdAtVUGSQTTGfzBTYRWV6gADHTufsE2 heMRaNBXKU6E3nT6mm5BJ8bKPqofqtFiDpoWHMJ3VGEZ4IAxMr7Lzq64/KqYqOTAAZ/d kJ/gORwx2ZrJWq/SsoH5LuqWen3Zw0vo0Lcnw4R01yQwOGrB99xeHBoGPlpDEYVAu0Aj O8w1Jqg6It/eIYmbJEjApAJJDHZfpeqYbAORqkaiLETzmhP84kUA3sCOeYgUXMX9tcag SuRQ== X-Gm-Message-State: AOJu0Yy51Ri3DACQYGC5fEsfbcIjTbvr6l+ir/8ciaCYuwdPUbCcPIVm 3+1L8STqgBQdZ4+LYC6/jVex2sFWu1gk5gdO3KaeSTQ7vU1GuyiEMipU6q2I9QVTdYK3+4zVAsP cwzhm8jziPrK4Znmx1ebJtTlRkVoDgAoVpRtSUdQnug== X-Gm-Gg: ATEYQzzBHhg8LdZY051Vg6hwGuzCNyGtj4j4Z87z5tRUO7L9UBYvZZuapsFuNsVATfH mBlnbUPKremu05wneRobKCsB+mMfMZbZW+sJXbj45yHXWfqipVzlw4OtKvFl3/1PaPdu9jdE9pG YCuyauaHF02ukUBQ7ibbDeqiGTdBU8kiX1pih7K/DIJ77lz7axBSdrgR82DAPVBwnj2ok2AZYsf AWaR9cujZjx7ST2vZC+w8BSaQqTcHzqrveLV23lJtYfJlvP85BatILXBUusajGqPQw4tYRd7xUr yzfqdds= X-Received: by 2002:a05:690e:b41:b0:64f:ffa1:5478 with SMTP id 956f58d0204a3-64fffa15521mr10037438d50.37.1774830756361; Sun, 29 Mar 2026 17:32:36 -0700 (PDT) Precedence: list list-help: list-unsubscribe: list-post: List-Id: x-ms-reactions: disallow MIME-Version: 1.0 References: <5ce1f5a3-1ad5-4cc7-8c6e-93170af28ef4@sandfox.me> In-Reply-To: <5ce1f5a3-1ad5-4cc7-8c6e-93170af28ef4@sandfox.me> Date: Mon, 30 Mar 2026 02:32:24 +0200 X-Gm-Features: AQROBzAxbzmH9ozYGb35KOn5xJYSRfMFjaXErN1WPglKkjiM3X_42wh4-gBfNFo Message-ID: Subject: Re: [PHP-DEV] RFC proposal: Invokable interface To: Anton Smirnov Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="000000000000c4f705064e32fc72" From: aldemeery@gmail.com (Osama Aldemeery) --000000000000c4f705064e32fc72 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Anton, Thank you for taking the time to respond. This is really helpful feedback, and I genuinely think the distinction you're drawing is an important one to get right. I think the parallel with Stringable holds more closely than it might seem. If we put them side by side: - Both are automatically implemented by the engine for classes that define the corresponding magic method. - Both can be explicitly implemented by users. - Both enforce the presence of a magic method. Stringable enforces __toString(), Invokable enforces __invoke(). - The argument that magic methods are just implementation details holds true for both. The only difference is that __toString() has a fixed signature, so Stringable can enforce it through a normal interface declaration. __invoke() doesn't have a fixed signature, so Invokable uses an enforcement handler instead. Different mechanism, same contract. The difference is caused by the variable signature, not by any fundamental difference in what the interface represents. The comparison to Throwable is interesting, but as far as I understand (and please correct me if I am wrong), Throwable restricts direct user implementation by design to keep the exception hierarchy clean and predictable. That said, I could be wrong about any of this, and in which case I would genuinely appreciate you correcting my reasoning. Regards, Osama Aldemeery On Mon, Mar 30, 2026 at 12:52=E2=80=AFAM Anton Smirnov = wrote: > Hi! > > On 30/03/2026 00:42, Osama Aldemeery wrote: > > It follows the Stringable pattern: auto-implemented for any class > > defining __invoke(), explicitly implementable with enforcement, and > > covariant to callable in return type checks. > > Stringable is just a normal interface that can be used directly as any > other regular interface, it's just also applied magically. > > Invokable cannot be a regular interface because the signature for > __invoke is not fixed, so it's a "weird" interface with magic behavior > like Throwable and Iterable. What is common about these weird interfaces > is that they can't be directly implemented by user. I don't feel like > breaking this rule is a good idea for something with no clear benefits. > > Second thing is that magic methods are not supposed to be used directly, > so having __invoke is just an implementation detail, the consumer code > should not check for that, that's a code smell. > > Anton > --000000000000c4f705064e32fc72 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Anton,

Thank you for taking the time to respond.This is really helpful feedback, and I genuinely think the distinction you= 're drawing is an important one to get right.

I think the parall= el with=C2=A0Stringable= =C2=A0holds more closely than it might seem.
If we put them side by side= :
  • Both are automatically implemented by the engine for classes t= hat define the corresponding magic method.
  • Both can be explicit= ly implemented by users.
  • Both enforce the presence of a magic metho= d.=C2=A0Stringable=C2=A0enforces=C2=A0__toString(),=C2=A0Invo= kable=C2=A0enforces=C2=A0__invoke().
  • The argument tha= t magic methods are just implementation details holds true for both.
  • The only difference is that=C2=A0__toString()=C2=A0has a fixed signature, so=C2=A0Stringable=C2=A0can enforce it = through a normal interface declaration.=C2=A0__invoke()=C2=A0doesn't have a fixed signature, s= o=C2=A0Invokable=C2=A0u= ses an enforcement handler instead.
    Different mechanism, same contract. = The=C2=A0difference is caused by the variable signature, not by any fundame= ntal difference in what the interface represents.

    The comparison to= =C2=A0Throwable=C2=A0is= interesting, but as far as I understand (and please correct me if I am wro= ng),=C2=A0Throwable=C2= =A0restricts direct user implementation by design to keep the exception hie= rarchy clean and predictable.

    That said, I could be wrong about any = of this, and in which case I would genuinely appreciate you correcting my r= easoning.

    Regards,

    Osama Aldemeery

On Mon, Mar 30, 2026 at 12:52=E2=80=AFAM Anton Smirnov <sandfox@sandfox.me> wrote:
Hi!

On 30/03/2026 00:42, Osama Aldemeery wrote:
> It follows the Stringable pattern: auto-implemented for any class
> defining __invoke(), explicitly implementable with enforcement, and > covariant to callable in return type checks.

Stringable is just a normal interface that can be used directly as any
other regular interface, it's just also applied magically.

Invokable cannot be a regular interface because the signature for
__invoke is not fixed, so it's a "weird" interface with magic= behavior
like Throwable and Iterable. What is common about these weird interfaces is that they can't be directly implemented by user. I don't feel li= ke
breaking this rule is a good idea for something with no clear benefits.

Second thing is that magic methods are not supposed to be used directly, so having __invoke is just an implementation detail, the consumer code
should not check for that, that's a code smell.

Anton
--000000000000c4f705064e32fc72--