php / php-tasks

Tasks that need doing. This is for php-src maintainers. The end-user bug tracker is at https://bugs.php.net/.
27 stars 6 forks source link

Resource to opaque object migration #6

Open Girgias opened 4 years ago

Girgias commented 4 years ago

A long term project is to move all extension resources to objects as they are all in all better.

This issue aims to list the remaining usages of resources within php-src

Related RFC: https://wiki.php.net/rfc/resource_to_object_conversion

PHP 8.0:

PHP 8.1:

Scheduled for PHP 8.4:

Scheduled for PHP 9.0:

Remaining:

Persistent resources that are only used internally and not exposed to userland:

remicollet commented 4 years ago

About ZIP, I don't know if it worth the work, as we already have a full OO API. Perhaps we should rather deprecate the old functional and minimal API.

kocsismate commented 4 years ago

@remicollet I was wondering about this a while ago. See my question at https://github.com/php/php-src/pull/5601#issuecomment-631681185

I even had a try at the conversion, but for me, it didn't go as easy as it seemed first, so I stopped. As far as I remember, my main problem was that the data structures used by the OO and procedural interface don't align really well.

Is it really the case? If so, then I'd also prefer deprecating the old API.

Ayesh commented 4 years ago

I apologize if this was discussed before.

Wouldn't it be appropriate to declare a ResourceInterface and have all the classes implement that? Methods such as ResourceInterface::close can provide a unified way to close resources, ResourceInterface::getId can return spl_object_id()-esque results, and serializers for example can refuse to serialize all \ResourceInterface instances.

Girgias commented 4 years ago

I apologize if this was discussed before.

Wouldn't it be appropriate to declare a ResourceInterface and have all the classes implement that? Methods such as ResourceInterface::close can provide a unified way to close resources, ResourceInterface::getId can return spl_object_id()-esque results, and serializers for example can refuse to serialize all \ResourceInterface instances.

The whole point of the migration is to move away from the legacy resource behaviour, moreover with objects all the x_close variants become no-ops.

Adding an OOP API to the opaque objects is also a completely orthogonal issue to moving resources to opaque objects.

And I'd rather that we have a long think about each individual API instead of just bundling a weird interface which will be mostly useless IMHO

Ayesh commented 4 years ago

With the curl class implementation, for example, is_resource() returns false for CurlHandle class objects. This means anyone who wants to check if a given variable is a resource (in a semantic sense) needs to use is_resource and instanceOf.

Having an interface means we will need only one instaceOf op, as opposed to every different class name the migration brings.

cmb69 commented 4 years ago

This means anyone who wants to check if a given variable is a resource […]

Why do you want to check this? Is there any reason not to check for !== false?

nikic commented 4 years ago

Because this is an anticipated failure mode of hosting this internal coordination tracker on GitHub, I'm going to err on the side of over-moderation and say: This is not the place to have this discussion. These issues have been discussed extensively on the PHP internals list in the past, and that would also be the place to revisit any decisions.

sgolemon commented 4 years ago

BZ2 should be filed under ext/standard/streams The only resources it interacts with are streams.

sgolemon commented 4 years ago

Regarding streams (which are going to be biggest PITA by far), I've been thinking it might make transition smoother (and make calling semantics generally nicer for extension authors) to add a new ZPP type F which returns a php_strea*, so:

  php_stream *stream;

  if (zend_parse_parameters(ZEND_NUM_ARGS(), "F", &stream) == FAILURE) {
    RETURN_THROWS();
  }

The idea being that we can update the rest of the runtime where streams are taken as arguments to remove any remaining hint of resources first, then work on the internals without a massive chunk of the userspace API breaking underneath us. Obviously a handful of functions will still need special attention (fclose(), a few stream_*() functions), but they'll be the minority.

We could even update the stubs file with a not-yet-extant "File" class and initially have the arginfo generator regard this as ZEND_ARG_TYPED_INFO(IS_RESOURCE), but when we do the big switchover, just have the generator now use ZEND_ARG_OBJ_INFO(File). Again, this should let us focus on the hard parts without being bogged down by a thousand callsites.

Edit to add: I just remembered why I never moved on this. php_stream is a PHP thing, Zend shouldn't call back to PHP. Back to the drawing board.

sgolemon commented 4 years ago

Okay, expanded idea:

typedef void* (zend_parse_param_callback*)(zval *arg);

// In zpp arg handler:
    case 'R': { /* Resolver */
        void **ptr = va_arg(*va, void **);
        zend_parse_param_callback *callback = va_arg(*va, zend_parse_param_callback*);

        *ptr = callback(arg);
        if (!*ptr) {
            ZEND_ASSERT(EG(exception));
            return "";
       }
       break;
    }

Then callsites look like:

{
    php_stream *stream;

    if (zend_parse_parameters(ZEND_NUM_ARGS(), "R", &stream, php_stream_from_zval) == FAILURE) {
        RETURN_THROWS();
    }
}

Edit to add: While php_stream_from_zval() doesn't currently throw exceptions, I'm sure we could use a version which does throw a proper TypeError.

sgolemon commented 4 years ago

On the other hand.... I've just actually sat down to do grep -r php_stream_to_zval ext/ | wc -l and the answer is only 60. So I may be making a tempest in a teapot.

jrfnl commented 4 years ago

For completeness of the list, the following extensions also saw resource to object changes in PHP 8.0:

The status of the Enchant extension is not 100% clear to me. The change from resource to object is mentioned in the changelog, but the associated PR discussion gives the impression that the commit got reverted: https://github.com/php/php-src/pull/5533

jrfnl commented 4 years ago

Another one for which I can't seem to determine the status is SNMP. I can see some PHP 8.0 commits mentioning a resource to object change, but I can't find an entry in the changelog, nor an associated PR:

Girgias commented 4 years ago

For completeness of the list, the following extensions also saw resource to object changes in PHP 8.0:

* GD, GdImage  - [php/php-src#4714](https://github.com/php/php-src/pull/4714)

* XML - [php/php-src#3526](https://github.com/php/php-src/pull/3526)

* XMLWriter - [php/php-src#4706](https://github.com/php/php-src/pull/4706)

The status of the Enchant extension is not 100% clear to me. The change from resource to object is mentioned in the changelog, but the associated PR discussion gives the impression that the commit got reverted: php/php-src#5533

Have a look at commit: https://github.com/php/php-src/commit/cd3e04dff375fbfaba37a4ae1c8ef1805f63c940 for Enchant

jrfnl commented 4 years ago

Thanks @Girgias !

cmb69 commented 4 years ago

Another one for which I can't seem to determine the status is SNMP.

Me neither, but it seems there is an OOP API as of PHP 5.4.0 (http://github.com/php/php-src/commit/5e82e334ddffcf577542a74a37f3388d14790686) which is not documented at all.

PS: oh, it is documented.

jrfnl commented 4 years ago

@cmb69 Thanks for taking a look! Still not entirely clear what the change in PHP 8.0 is related to that. Let's hope someone figures it out and adds it to the changelog (if relevant enough) ;-)