Skip to content

ReflectionClass::isInstantiable() is wrong about internal classes that prevent instantiation #17796

Open
@DanielEScherzer

Description

@DanielEScherzer

Test script:

<?php

$classes = get_declared_classes();

foreach ( $classes as $clazz ) {
    $r = new ReflectionClass( $clazz );
    if ( !$r->isInstantiable() ) {
        continue;
    }
    try {
        new $clazz();
    } catch ( ArgumentCountError|TypeError $e ) {
        // Nothing
    } catch ( Throwable $e ) {
        echo $clazz . ": ";
        echo get_class( $e ) . ': ' . $e->getMessage() . "\n";
    }
}

Failures

For each of the following classes, ReflectionClass::isInstantiable() returns true, but trying to create an instance of the class directly fails:

Generator: Error: The "Generator" class is reserved for internal use and cannot be manually instantiated
WeakReference: Error: Direct instantiation of WeakReference is not allowed, use WeakReference::create instead
FiberError: Error: The "FiberError" class is reserved for internal use and cannot be manually instantiated
InflateContext: Error: Cannot directly construct InflateContext, use inflate_init() instead
DeflateContext: Error: Cannot directly construct DeflateContext, use deflate_init() instead
CurlHandle: Error: Cannot directly construct CurlHandle, use curl_init() instead
CurlMultiHandle: Error: Cannot directly construct CurlMultiHandle, use curl_multi_init() instead
CurlShareHandle: Error: Cannot directly construct CurlShareHandle, use curl_share_init() instead
CurlSharePersistentHandle: Error: Cannot directly construct CurlSharePersistentHandle, use curl_share_init_persistent() instead
Dba\Connection: Error: Cannot directly construct Dba\Connection, use dba_open() or dba_popen() instead
FFI: Error: Instantiation of FFI is not allowed
FFI\CData: Error: Instantiation of FFI\CData is not allowed
FFI\CType: Error: Instantiation of FFI\CType is not allowed
FTP\Connection: Error: Cannot directly construct FTP\Connection, use ftp_connect() or ftp_ssl_connect() instead
LDAP\Connection: Error: Cannot directly construct LDAP\Connection, use ldap_connect() instead
LDAP\Result: Error: Cannot directly construct LDAP\Result, use the dedicated functions instead
LDAP\ResultEntry: Error: Cannot directly construct LDAP\ResultEntry, use the dedicated functions instead
Directory: Error: Cannot directly construct Directory, use dir() instead
Odbc\Connection: Error: Cannot directly construct Odbc\Connection, use odbc_connect() or odbc_pconnect() instead
Odbc\Result: Error: Cannot directly construct Odbc\Result, use an appropriate odbc_* function instead
PDORow: PDOException: You may not create a PDORow manually
PgSql\Connection: Error: Cannot directly construct PgSql\Connection, use pg_connect() or pg_pconnect() instead
PgSql\Result: Error: Cannot directly construct PgSql\Result, use a dedicated function instead
PgSql\Lob: Error: Cannot directly construct PgSql\Lob, use pg_lo_open() instead
Shmop: Error: Cannot directly construct Shmop, use shmop_open() instead
Soap\Url: Error: Cannot directly construct Soap\Url
Soap\Sdl: Error: Cannot directly construct Soap\Sdl
SysvMessageQueue: Error: Cannot directly construct SysvMessageQueue, use msg_get_queue() instead
SysvSemaphore: Error: Cannot directly construct SysvSemaphore, use sem_get() instead
SysvSharedMemory: Error: Cannot directly construct SysvSharedMemory, use shm_attach() instead
XMLParser: Error: Cannot directly construct XMLParser, use xml_parser_create() or xml_parser_create_ns() instead

Not all of these extensions are on 3v4l but those that are can be confirmed at https://3v4l.org/BmAkH

I didn't test all extensions, what I have enabled locally is:

root@c1c025bca24f:/usr/src/php# php -i | grep "Configure Command"
Configure Command =>  './configure'  '--enable-fpm' '--with-pdo-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-pgsql' '--with-pdo-pgsql' '--with-pdo-sqlite' '--enable-intl' '--without-pear' '--with-jpeg' '--with-webp' '--with-avif' '--with-freetype' '--with-xpm' '--enable-exif' '--with-zip' '--with-zlib' '--enable-soap' '--enable-xmlreader' '--with-xsl' '--with-tidy' '--enable-sysvsem' '--enable-sysvshm' '--enable-shmop' '--enable-pcntl' '--enable-mbstring' '--with-curl' '--with-gettext' '--with-bz2' '--with-gmp' '--enable-bcmath' '--enable-calendar' '--enable-ftp' '--with-enchant=/usr' '--enable-sysvmsg' '--with-ffi' '--enable-zend-test' '--enable-dl-test=shared' '--with-ldap' '--with-ldap-sasl' '--with-password-argon2' '--with-mhash' '--with-sodium' '--enable-dba' '--with-cdb' '--enable-flatfile' '--enable-inifile' '--with-tcadb' '--with-lmdb' '--with-qdbm' '--with-snmp' '--with-unixODBC' '--with-pdo-odbc=unixODBC,/usr' '--with-config-file-path=/etc' '--with-config-file-scan-dir=/etc/php.d' '--with-pdo-firebird' '--with-pdo-dblib' '--enable-debug' '--disable-zts'

Proposal

I propose that we add a new class flag, ZEND_ACC_NON_INSTANTIABLE, that classes can apply when they are registered.

PHP Version

65d4331

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions