Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:108539 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 41721 invoked from network); 13 Feb 2020 16:52:02 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 13 Feb 2020 16:52:02 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 8A06D18050A for ; Thu, 13 Feb 2020 07:06:28 -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=0.5 required=5.0 tests=BAYES_20, FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM,HEADER_FROM_DIFFERENT_DOMAINS, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE, SPF_PASS 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-wr1-f43.google.com (mail-wr1-f43.google.com [209.85.221.43]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 13 Feb 2020 07:06:28 -0800 (PST) Received: by mail-wr1-f43.google.com with SMTP id y11so7082633wrt.6 for ; Thu, 13 Feb 2020 07:06:28 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=I1yZByKLKW0IkArLjeJxuyo18JwQZ3BwBGxbLRZ9POE=; b=kOpKOJNRxgAJK9PUFVj0tpwBhdSvq9TOlKnYKaYz5Fn0CAM0e7CM+ZHkxs6JOlM+b5 800meRbfNpouO341mJGJ+nQRGGiOSDiib0dGnKgFkp3uQ13K01U8O1UPSlh8teJDdfxv rM/pAHVF4ZRhvv7MYgzmT+3hs3xwYnup0+PxohCfdXE7gjMEu8FzTQ27J8IJascR2A4v idIf3HmH9oBaEy4yoI44kkzLvbFjF1arTlnENXW8U5qNVJhJYcoaKFTDmI74MDG1Tl0a 5tP1140y1IwSPTgjcA2Z9Tizch+CBZSTuDcsOL7li2E8m9WlJcVEgOgWX+MS8g/FqGeH vk6Q== X-Gm-Message-State: APjAAAUg2/KuyT+vWuH/TxxNtWo7H1ldFU0dijAWTQeQjPTPj4+XtQ8a TlppfGFioaB+flUR8sGhHIHjkf1iMxOUoK2kzGhrb8k7tQ== X-Google-Smtp-Source: APXvYqxNuLQUOHrLh2I29BSwdjVh8HdDNk5xziT6lKf2awNVT0maNyICQd/hjU28DmDg+/biii4seaBLPbai9MdGK2U= X-Received: by 2002:a5d:6a88:: with SMTP id s8mr22090971wru.173.1581606386259; Thu, 13 Feb 2020 07:06:26 -0800 (PST) MIME-Version: 1.0 Date: Thu, 13 Feb 2020 16:04:36 +0100 Message-ID: To: PHP Development Content-Type: multipart/alternative; boundary="000000000000d3dcb3059e766e41" Subject: Re: [RFC] Adding a "Stringable" interface to PHP 8 From: patrickallaert@php.net (Patrick ALLAERT) --000000000000d3dcb3059e766e41 Content-Type: text/plain; charset="UTF-8" Hi, > allow using string|Stringable to express string|object-with-__toString() That goal is expressed in a technical way, rather than a functional one. I have the feeling that addressing the goal: "Can I represent/cast variable $str as a string" would address a broader, yet much more useful, scope. string|Stringable: 1. Denotes a list of types, not a capability as "stringable" would as a virtual type (like iterable). It somewhat contradicts the principle of knowing the *type* vs knowing what we can do with it. 2. Is incomplete in terms of what can be "represented as a string". The Stringable interface used alone tells there is a __toString() method. Therefor, we should expect it to be used to call the __toString() method explicitly: function test(Stringable $object) { \strtoupper($object->__toString();) // do something with __toString(); } ... in order to be consistent with what interfaces are meant. If mainly used for string casting capability, then it will only match objects and not all the other types that can be casted as string. A virtual "stringable" type (that would be similar to "iterable)" would, IMHO, be of a bigger benefit if it is to denote the fact that "a variable can be transformed to a string". By design, when a variable is declared as "iterable", you know you can foreach() on it now, but also on other yet-to-be-implemented concepts that would support foreach looping. Think about it as if generators would have appeared after "iterable" keyword and then, added to it. > Adding a new stringable special type (like iterable, callable, etc.) is not considered in this RFC because it would require adding a new reserved keyword in the language. This would break BC more heavily and would defeat goal #2 mentioned previously (ability to polyfill on PHP7.) It's perfectly fine to add a new reserved keyword in the language, and a major version is absolutely the best moment for it. Not sure how much more break would be implied by a keyword, vs the interface. As it is presented, Stringable alone seems of very little use as compared to union like "string|Stringable", so using the polyfill in a version of PHP that does not support union does not seem to make sense. What is the real advantage of adding this to the core, rather than some FIG/PSR standard? This would be compatible in both current versions of PHP and next ones at the same time. This RFC would also introduce a very new concept, which seems nice at a first glance, but a bit nasty too: class Foo { /** @deprecated */ public string __toString() { throw new \Exception("Foo should not be casted to string, you should now..."); } } The above would imply that "Foo implements Stringable" unconditionally: without opt-in, but also without opt-out! It would also be the only one case of classes declared without "implements" that would still implement an interface: quite contradictory and hacky! It would be less "hacky" if a broader concept (let's say "Signature"?) would exist for checking at runtime the availability of a method without requiring an interface to be implemented, e.g.: Option 1: By introducing the "signature" keyword: signature CanCommit { public function commit(); } used like this: if ($object instanceof CanCommit) { $object->commit(); } Option 2: By introducing an extra meaning to keyword "implements": interface CanCommit { public function commit(); } used like this: if ($object implements CanCommit) { // Checking at runtime that $object's class would comply to interface CanCommit $object->commit(); } If this, or a similar concept would exist, one could just declare a signature for __toString() and we wouldn't have the incoherence that this RFC introduces. Another, also broader, approach would be to implement a global way to check "castability" to type X: function foo((string) $stringable) { // Type not enforced, but possibility of casting checked } I'm aware that this RFC addresses a small goal, but accepting lot of small changes compared to bigger ones with a broader vision could lead to even more inconsistencies in the core in the longer run. Regards, Patrick --000000000000d3dcb3059e766e41--