Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:118930 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 55106 invoked from network); 31 Oct 2022 19:38:25 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 31 Oct 2022 19:38:25 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 034F61804FF for ; Mon, 31 Oct 2022 12:38:24 -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=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,HTML_MESSAGE,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS36483 23.83.216.0/22 X-Spam-Virus: No X-Envelope-From: Received: from boar.tulip.relay.mailchannels.net (boar.tulip.relay.mailchannels.net [23.83.218.250]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 31 Oct 2022 12:38:21 -0700 (PDT) X-Sender-Id: dreamhost|x-authsender|josh@joshbruce.dev Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 292C26414F2; Mon, 31 Oct 2022 19:38:18 +0000 (UTC) Received: from pdx1-sub0-mail-a241 (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 96A48640BEA; Mon, 31 Oct 2022 19:38:17 +0000 (UTC) ARC-Seal: i=1; s=arc-2022; d=mailchannels.net; t=1667245097; a=rsa-sha256; cv=none; b=cq26oWVUhakWJsy1UhiMQO+4PV2lf5h001oF9E7rQydiFWUqEl06I1+2wYOo6+haryK8kD L1XP+cKlxRW8qPvC5uwc1Smn08m/05P45WE/8rOKtMnD8OYZBRLRA83CGSyyBC3edYaAWB JUkCLXpYe0tqYvQ51KG/OkjZK+bpxOujc0pdpU/sO0AfU+bLLdd9NUZpggB/CJAKE/SOe5 ++16k8VMLVp05FoZMA5HGRUI1WeR9X0PY9juelBDgBQ7E1pHZ+coTYxKjT2/5VB0LQus2S BbQPd+oD5m43nlbFIUFqoRo8GNwWPHLRGDBBuQy4DWMfhqjVSFSvTgEr1H2tZw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=mailchannels.net; s=arc-2022; t=1667245097; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references:dkim-signature; bh=Gz20f+/LUT1V82ER7+M9OMdJakFzBzLWmA8TJS1LXkA=; b=1TfsyiUpZiMFsNzFLsxgdsuRJhLt+MdjRGHNcKcPFl8RjNE9Ep73/t6Qs453cCiBr1Q62h CYVznz0qxcss+L6QTcd/JyNAwEm9QVCHGQjpQ4M1dkoHH4IREDp30LNrTCqfK6HWskYDj3 gQscFAmCDSzQjX12KJ+fCnMUI/vO/GKtKI6TWZUMy/im2muSy+IZbn6pv6ZIl6B5ySpkUC V3T4osih6alhS+j1wZSGt2jQUAPi8MVultoNNLbITr2PbE2uRjcVQvMR12cv3PHiYPG/vx FDOvNiOOMNhert7KXyAJcDmUgLkk1MypcRW50pJuHvmYUcyCV1t22gRXyxy1tw== ARC-Authentication-Results: i=1; rspamd-7fb88f4dd5-lxz94; auth=pass smtp.auth=dreamhost smtp.mailfrom=josh@joshbruce.dev X-Sender-Id: dreamhost|x-authsender|josh@joshbruce.dev X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|josh@joshbruce.dev X-MailChannels-Auth-Id: dreamhost X-Abortive-Left: 63c438de5b4f3b52_1667245097867_3595086808 X-MC-Loop-Signature: 1667245097867:3261782038 X-MC-Ingress-Time: 1667245097867 Received: from pdx1-sub0-mail-a241 (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.122.64.69 (trex/6.7.1); Mon, 31 Oct 2022 19:38:17 +0000 Received: from smtpclient.apple (111.sub-75-244-34.myvzw.com [75.244.34.111]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) (Authenticated sender: josh@joshbruce.dev) by pdx1-sub0-mail-a241 (Postfix) with ESMTPSA id 4N1Njj07dKz30; Mon, 31 Oct 2022 12:38:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=joshbruce.dev; s=dreamhost; t=1667245097; bh=Gz20f+/LUT1V82ER7+M9OMdJakFzBzLWmA8TJS1LXkA=; h=From:Content-Type:Subject:Date:Cc:To; b=YDs8tX2fQM1GfFPHiLQuDV1d2991uNUgoHyzxJIKJgDlgFMmF58bIPLKL5vYaVrh4 LupqGBLKyS1fVzm0wAVjbbeZq0Txq0191NKrY6VN4BMVME/pSf5w/GlNQ5Casr8b84 kMATRgBCIZjMCzAiaEgGav8C2mvdaq2Wx3mzSOexOE8U0Pl+u69WCxYGIFBKUYpFTz pVspqkZdb9/aD/Dqx/UaIP4OBSxFoXN0Hc3PPVhUZ3S96Oc2vxqQeug+MwwhVVtmRB 2f9Mfmt3ZcyWQP4yG/dZGk74Lodgkxj8ICubS6lXVH/OC9lUNt75ZYUYDv85zkH2Hs O4IyaMrtpmptA== Message-ID: Content-Type: multipart/alternative; boundary="Apple-Mail=_1E0D3AEB-1A76-4D99-8E72-D97F934CA9C8" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3731.200.110.1.12\)) Date: Mon, 31 Oct 2022 15:38:05 -0400 In-Reply-To: <94DC0839-E43B-4F3A-9105-8F3CB9D7BBC1@joshbruce.dev> Cc: php internals To: Josh Bruce References: <21C5073D-3F39-49DA-8686-E027AE780793@joshbruce.dev> <1bc7759a-63b8-4b96-bb69-97b50f851307@www.fastmail.com> <94DC0839-E43B-4F3A-9105-8F3CB9D7BBC1@joshbruce.dev> X-Mailer: Apple Mail (2.3731.200.110.1.12) Subject: Re: [PHP-DEV] [RFC][Discussion] Objects can be declared falsifiable From: josh@joshbruce.dev (Josh Bruce) --Apple-Mail=_1E0D3AEB-1A76-4D99-8E72-D97F934CA9C8 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 Hello Interntals, Someone reached out to me outside of internals regarding the RFC I = submitted on being able to declare objects falsifiable, so, I decided to = update and re-enter the fray. I=E2=80=99ve updated the references section as many of the RFCs that = were under discussion at the time have since been implemented. I still find myself in situations where having the capability would be = beneficial. Specifically, I=E2=80=99m noticing with API responses where = I want to pass the body received from a ResponseInterface the object can = check itself. I currently use methods such as: ->isValid() ->isInvalid() ->toBool() And similar - the isValid and isInvalid() methods are just aliases of = toBool(), which speaks to the ability for adopters to make their = interfaces compatible without breaking changes in their code. In the case of a conditional - looks like this: $obj =3D Object::init($response); If ($obj->isValid()) { // do something with $obj } Or: If ( $obj =3D Object::init($response) and $obj->isValid() ) { // do something with $obj } Would like to be able to do something like: If ($obj =3D Object::init($response)) { // do something with $obj } As of today, the last example is always true. You wouldn=E2=80=99t be = able to create a guard clause for the negation: If ( $obj =3D Object::init($response) and $obj =3D=3D=3D false ) { // handle invalid object, which could include something like = $obj->failed() } Cheers, Josh > On Sep 26, 2020, at 5:20 PM, Josh Bruce wrote: >=20 > Hey Internals, >=20 > So, I received a message that said of the mail I should have received = from internals bounced; so, this is part test and part update. >=20 > I=E2=80=99ve started mapping out call paths in the project that = brought this concept to light. >=20 > The project, Shoop, never uses is_bool() - instead it always uses = empty, then reverses that for: >=20 > 1. Booleans > 2. Numbers > 3. Arrays > 4. Strings > 5. stdClass or data-only classes > 6. Json strings, which it treats as #5 >=20 > I essentially get standard SPL behavior when I do this. >=20 > For the object definition I can define two interfaces: >=20 > 1. Falsifiable > 2. Emptiable >=20 > The checks go like this: >=20 > 1. if the object implements Falsifiable: the __toBool method would be = called and would return the result. (This check would be inside = is_bool() and could use the empty() implementation) > 2. if the object implements Emptiable: the __isempty method would be = called and return the result. (This check would be inside empty()) > 3. else: standard output from is_bool() or empty() would be used when = passing an instance to either of those SPL functions, depending on which = the user is using. >=20 > Because the concepts of emptiness and falsiness are so tightly = coupled, I=E2=80=99m wondering if it would be better to implement both = with this RFC?? >=20 > Otherwise, Emptiable would be a future enhancement consideration. >=20 > I=E2=80=99d like to hear what the rest of Internals thinks. >=20 > Next for me: I=E2=80=99m going to finish solidifying the Shoop project = and make sure my other projects can use latest and then continue going = through the tutorials from Nikita and others on doing development = Internals. >=20 > Cheers, > Josh >=20 >> On Aug 30, 2020, at 9:32 AM, Josh Bruce > wrote: >>=20 >> Hey Tyson, >>=20 >> This is great! Thank you so much, sincerely. >>=20 >> Still slow goings, which is fine, we have at least a year. lol >>=20 >> Static analyzers seem to be the biggest concern to date. >>=20 >> Haven=E2=80=99t been able to get one running locally - though I=E2=80=99= ve only spent a few minutes here and there; definitely on the list. >>=20 >> A use case for this sort of thing is also a concern or question. I = came across Pipeline from the PHP League and saw their interruptible = processor and was wondering if something like this would be helpful = there - for pipeline patterns in general: = https://github.com/thephpleague/pipeline/blob/master/src/InterruptibleProc= essor.php >>=20 >> While working on another project, saw this line from the PHP = array_filter docs: >>=20 >> "If no callback is supplied, all entries of array equal to FALSE = (see converting to boolean) will be removed." >>=20 >> I=E2=80=99m still field testing the latest iteration of my base = project, but wanted to put a working (non-internals) implementation out = there (note this covers emptiness and falseness for the purposes of the = project): >>=20 >> Tests - = https://github.com/8fold/php-shoop/blob/master/tests/RfcObjectCanBeDeclare= dFalsifiableTest.php >>=20 >> Interface - = https://github.com/8fold/php-shoop/blob/master/src/FilterContracts/Interfa= ces/Falsifiable.php - for our purposes the efToBool would be __toBool >>=20 >> Default implementation - = https://github.com/8fold/php-shoop/blob/master/src/Shooped.php#L216 >>=20 >> =E2=80=9CType system=E2=80=9D implementation - = https://github.com/8fold/php-shoop/blob/master/src/Filter/TypeAsBoolean.ph= p >>=20 >> Cheers, >> Josh >>=20 >>> On Aug 9, 2020, at 3:59 PM, tyson andre > wrote: >>>=20 >>> Hi Josh, >>>=20 >>> I'd recommend looking at https://github.com/php/php-src/pull/5156 = (linked to in your RFC's reference) when implementing this PR. >>> Additionally, I didn't see if this was brought up - PHP already has = a class which is falsifiable - SimpleXMLElement. >>>=20 >>> You can see the source of ext/simplexml/simplexml.c for `_IS_BOOL` >>>=20 >>> ``` >>> static int sxe_object_cast_ex(zend_object *readobj, zval *writeobj, = int type) >>> { >>> php_sxe_object *sxe; >>> xmlChar *contents =3D NULL; >>> xmlNodePtr node; >>> int rv; >>>=20 >>> sxe =3D php_sxe_fetch_object(readobj); >>>=20 >>> if (type =3D=3D _IS_BOOL) { >>> node =3D php_sxe_get_first_node(sxe, NULL); >>> if (node) { >>> ZVAL_TRUE(writeobj); >>> } else { >>> ZVAL_BOOL(writeobj, = !sxe_prop_is_empty(readobj)); >>> } >>> return SUCCESS; >>> } >>> ``` >>>=20 >>> ``` >>> static php_sxe_object* php_sxe_object_new(zend_class_entry *ce, = zend_function *fptr_count) >>> intern->zo.handlers =3D &sxe_object_handlers; >>> // ... elsewhere in ext/simplexml/simplexml.c >>> sxe_object_handlers.cast_object =3D sxe_object_cast; >>> ``` >>>=20 >>> The default handlers would be overridden, so this would probably = need to fall back to the original handlers for types other than bool. >>> Also, this might need to copy all of the handlers from the parent = class entry's zend_object_handlers, >>> to meet the expected behavior of other cast types and other magic = behaviors from SimpleXMLElement and other classes continuing to work. >>>=20 >>> =46rom the perspective of static analysis, a few things to note: >>> - Static analyzers such as psalm/phan currently deliberately don't = bother handling the possibility that `object` can be false even after it = was checked for falsiness. >>> There's hundreds of other things that could be implemented, and = adding the special casing and performance overhead checking for FFI = objects and SimpleXMLElement, subclasses of those is currently low = priority compared to those things. >>>=20 >>> Code using SimpleXMLElement/FFI is generally limited to a few files = in practice. >>>=20 >>> Definitely possible for analyzers to support this for known base = classes, though, and the priority would increase if the RFC passed. >>>=20 >>> I am a maintainer of Phan. >>> - For BC reasons, internal data structures such as ArrayObject = probably wouldn't get changed in any php release >>> (e.g. could break code using falsiness check instead of null = check). >>> So this might lead to inconsistencies with newer extensions if = half of the data structures treat emptiness as false and half don't. >>> - This feature may end up getting adopted in cases where it's = convenient but turns out prone to accidental bugs and later is = deprecated and removed. >>> For example, = https://stackoverflow.com/questions/25031236/if-elem-vs-elem-is-not-none = was seen in python >>>=20 >>> (e.g. `if (!$this->resultSetObject) { $this->resultSetObject =3D = slow_db_operation(); }` >>> would not behave the way people would previously expect for most = objects (executed repeatedly instead of once)) >>>=20 >>> ``` >>> >> function test(SimpleXMLElement $e) { >>> // False positive RedundantCondition in psalm >>> if ($e) { >>> } >>> } >>> ```=20 >>>=20 >>>> And I don=E2=80=99t know of a way to add an interface to new = stdClass() - but thought this might be a valid use case: >>>=20 >>> `stdClass` isn't a final class. I assume they meant this >>>=20 >>> ``` >>> class EmptyStdClass extends stdClass implements Falsifiable { >>> public function __toBool() { return false; } >>> } >>> function example(stdClass $s) { >>> if (!$s) { throw new Exception("Previously impossible"); } >>> } >>> ``` >>>=20 >>> Thanks, >>> - Tyson >>> -- >>> PHP Internals - PHP Runtime Development Mailing List >>> To unsubscribe, visit: https://www.php.net/unsub.php >>>=20 >>=20 >=20 --Apple-Mail=_1E0D3AEB-1A76-4D99-8E72-D97F934CA9C8--