Since this topic fits like a glove, just dropping the "why I don't use
`__toString()`" argument here:
https://github.com/ShittySoft/symfony-live-berlin-2018-doctrine-tutorial/pull/3#issuecomment-460085493

A falsifiable object is worse than `__toString()` in this context, IMO.

Marco Pivetta

https://twitter.com/Ocramius

https://ocramius.github.io/


On Mon, 31 Oct 2022 at 20:38, Josh Bruce <j...@joshbruce.dev> wrote:

> 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’ve 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’m 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 = Object::init($response);
> If ($obj->isValid()) {
>     // do something with $obj
> }
>
> Or:
>
> If (
>     $obj = Object::init($response) and
>     $obj->isValid()
> ) {
>     // do something with $obj
> }
>
> Would like to be able to do something like:
>
> If ($obj = Object::init($response)) {
>     // do something with $obj
> }
>
> As of today, the last example is always true. You wouldn’t be able to
> create a guard clause for the negation:
>
> If (
>     $obj = Object::init($response) and
>     $obj === false
> ) {
>     // handle invalid object, which could include something like
> $obj->failed()
> }
>
> Cheers,
> Josh
>
> > On Sep 26, 2020, at 5:20 PM, Josh Bruce <j...@joshbruce.dev> wrote:
> >
> > Hey Internals,
> >
> > 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.
> >
> > I’ve started mapping out call paths in the project that brought this
> concept to light.
> >
> > The project, Shoop, never uses is_bool() - instead it always uses empty,
> then reverses that for:
> >
> > 1. Booleans
> > 2. Numbers
> > 3. Arrays
> > 4. Strings
> > 5. stdClass or data-only classes
> > 6. Json strings, which it treats as #5
> >
> > I essentially get standard SPL behavior when I do this.
> >
> > For the object definition I can define two interfaces:
> >
> > 1. Falsifiable
> > 2. Emptiable
> >
> > The checks go like this:
> >
> > 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.
> >
> > Because the concepts of emptiness and falsiness are so tightly coupled,
> I’m wondering if it would be better to implement both with this RFC??
> >
> > Otherwise, Emptiable would be a future enhancement consideration.
> >
> > I’d like to hear what the rest of Internals thinks.
> >
> > Next for me: I’m 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.
> >
> > Cheers,
> > Josh
> >
> >> On Aug 30, 2020, at 9:32 AM, Josh Bruce <j...@joshbruce.dev <mailto:
> j...@joshbruce.dev>> wrote:
> >>
> >> Hey Tyson,
> >>
> >> This is great! Thank you so much, sincerely.
> >>
> >> Still slow goings, which is fine, we have at least a year. lol
> >>
> >> Static analyzers seem to be the biggest concern to date.
> >>
> >> Haven’t been able to get one running locally - though I’ve only spent a
> few minutes here and there; definitely on the list.
> >>
> >> 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/InterruptibleProcessor.php
> >>
> >> While working on another project, saw this line from the PHP
> array_filter docs:
> >>
> >>     "If no callback is supplied, all entries of array equal to FALSE
> (see converting to boolean) will be removed."
> >>
> >> I’m 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):
> >>
> >> Tests -
> https://github.com/8fold/php-shoop/blob/master/tests/RfcObjectCanBeDeclaredFalsifiableTest.php
> >>
> >> Interface -
> https://github.com/8fold/php-shoop/blob/master/src/FilterContracts/Interfaces/Falsifiable.php
> - for our purposes the efToBool would be __toBool
> >>
> >> Default implementation -
> https://github.com/8fold/php-shoop/blob/master/src/Shooped.php#L216
> >>
> >> “Type system” implementation -
> https://github.com/8fold/php-shoop/blob/master/src/Filter/TypeAsBoolean.php
> >>
> >> Cheers,
> >> Josh
> >>
> >>> On Aug 9, 2020, at 3:59 PM, tyson andre <tysonandre...@hotmail.com
> <mailto:tysonandre...@hotmail.com>> wrote:
> >>>
> >>> Hi Josh,
> >>>
> >>> 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.
> >>>
> >>> You can see the source of ext/simplexml/simplexml.c for `_IS_BOOL`
> >>>
> >>> ```
> >>> static int sxe_object_cast_ex(zend_object *readobj, zval *writeobj,
> int type)
> >>> {
> >>>     php_sxe_object *sxe;
> >>>     xmlChar        *contents = NULL;
> >>>     xmlNodePtr          node;
> >>>     int rv;
> >>>
> >>>     sxe = php_sxe_fetch_object(readobj);
> >>>
> >>>     if (type == _IS_BOOL) {
> >>>             node = php_sxe_get_first_node(sxe, NULL);
> >>>             if (node) {
> >>>                     ZVAL_TRUE(writeobj);
> >>>             } else {
> >>>                     ZVAL_BOOL(writeobj, !sxe_prop_is_empty(readobj));
> >>>             }
> >>>             return SUCCESS;
> >>>     }
> >>> ```
> >>>
> >>> ```
> >>> static php_sxe_object* php_sxe_object_new(zend_class_entry *ce,
> zend_function *fptr_count)
> >>>     intern->zo.handlers = &sxe_object_handlers;
> >>> // ... elsewhere in ext/simplexml/simplexml.c
> >>>     sxe_object_handlers.cast_object = sxe_object_cast;
> >>> ```
> >>>
> >>> 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.
> >>>
> >>> From 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.
> >>>
> >>>  Code using SimpleXMLElement/FFI is generally limited to a few files
> in practice.
> >>>
> >>>  Definitely possible for analyzers to support this for known base
> classes, though, and the priority would increase if the RFC passed.
> >>>
> >>>  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
> >>>
> >>>  (e.g. `if (!$this->resultSetObject) { $this->resultSetObject =
> slow_db_operation(); }`
> >>>  would not behave the way people would previously expect for most
> objects (executed repeatedly instead of once))
> >>>
> >>> ```
> >>> <?php
> >>> function test(SimpleXMLElement $e) {
> >>>    // False positive RedundantCondition in psalm
> >>>    if ($e) {
> >>>    }
> >>> }
> >>> ```
> >>>
> >>>> And I don’t know of a way to add an interface to new stdClass() - but
> thought this might be a valid use case:
> >>>
> >>> `stdClass` isn't a final class. I assume they meant this
> >>>
> >>> ```
> >>> class EmptyStdClass extends stdClass implements Falsifiable {
> >>>    public function __toBool() { return false; }
> >>> }
> >>> function example(stdClass $s) {
> >>>    if (!$s) { throw new Exception("Previously impossible"); }
> >>> }
> >>> ```
> >>>
> >>> Thanks,
> >>> - Tyson
> >>> --
> >>> PHP Internals - PHP Runtime Development Mailing List
> >>> To unsubscribe, visit: https://www.php.net/unsub.php
> >>>
> >>
> >
>
>

Reply via email to