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