Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:113977 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 56306 invoked from network); 6 Apr 2021 08:10:01 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 6 Apr 2021 08:10:01 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id DEC141804E2 for ; Tue, 6 Apr 2021 01:08:59 -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,FREEMAIL_FROM,NICE_REPLY_A, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE, SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from mail-ej1-f42.google.com (mail-ej1-f42.google.com [209.85.218.42]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 6 Apr 2021 01:08:59 -0700 (PDT) Received: by mail-ej1-f42.google.com with SMTP id ap14so20516348ejc.0 for ; Tue, 06 Apr 2021 01:08:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-transfer-encoding:content-language; bh=3QDBM7i74IFb+MF3dbTak5TMt8nT61RXYMYLzS4DD8Q=; b=BWrLS4cxIdrAHVZTVMyEhG0dt5XbZpBknM/VK4UM8x38QHwvq4nAysr9F/ZDVI25Uh 3Eh5flongReMWDBvloIPB5Pu/7A24lOJArWo8R9y/QV8Y1LZcfC/GCfS1ZFP2mAlobY4 z9NUCCTGJLWbXSSqS1JFtBPHz1y7lSHU9Zkm+4c0vpr8BMi9NxYRp2HwSMJs5xZcB6hn lM5RQo3ZCz8yyCSSIf82HORWUaOlAZ660SBc62pcEFHx9/sSwG5gJGCmkca3A/BpW1VV QPysGQAWRKRFib+aI3Q83qkRRxGGuBTh29SUQtKMZJNQo3EnSdnO11RBpTDGinJrDB8q D3nQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-transfer-encoding :content-language; bh=3QDBM7i74IFb+MF3dbTak5TMt8nT61RXYMYLzS4DD8Q=; b=U2+HHatC6JswjM7ebb4dlztxlPY/7WN9iTirbO7QxNpi/8npaYCZfMvaPZJ7eYTONc NrM8dARbf6izwJr2kOcNyySusejfSk5khplp+mNFZEuJs8PyH8AjLbeJoZZuJvsstCx8 EpfEo4iNkVim2dsCmpDz9gmRcDOK5xiUtRoaUgeRJkMMgT5Le7z2fU46WfjqXr7FNO0V mmV7qhCbkYm7X/kfWrqVgm6jmboQo5tcy0X0hsAplLb8LVc7py6lgzOPh3l0pHs6EeWG rTJFCJdqQe1FTJIUHIcVqheVS8nX6xY9OwQR6QqXzdByo7OJizrRqGPPaMvFgPhEs0MD 1eBw== X-Gm-Message-State: AOAM532+/2PQ1OS5zAW2NIe6No2XoFf7b4ZsutfxT36FeEjXIaFAI1BH cX+ESgvIibgnpCDI0D6soBLjb7z4jds= X-Google-Smtp-Source: ABdhPJyuwjoazwC6TVYdteh530ZKfBCtTsNnZdOKalTa5Ue24FpNNIa99+xG5n2Q2WABf+K8zswhfw== X-Received: by 2002:a17:907:7799:: with SMTP id ky25mr32616917ejc.217.1617696535897; Tue, 06 Apr 2021 01:08:55 -0700 (PDT) Received: from [192.168.0.22] (cpc104104-brig22-2-0-cust548.3-3.cable.virginm.net. [82.10.58.37]) by smtp.googlemail.com with ESMTPSA id n10sm69079ejg.124.2021.04.06.01.08.55 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 06 Apr 2021 01:08:55 -0700 (PDT) To: internals@lists.php.net References: <0c5e70d7-5b11-5251-4ec9-608db63105c9@gmail.com> Message-ID: Date: Tue, 6 Apr 2021 09:08:58 +0100 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Thunderbird/78.9.0 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Content-Language: en-GB Subject: Re: [PHP-DEV] Path forward for class_exists with different targeted PHP version implementations From: rowan.collins@gmail.com (Rowan Tommins) On 06/04/2021 02:00, Jesse Rushlow wrote: > As an example, when the user runs "make:command"; we check if they > have PHP 8 && if "class_exists(Symfony\.....\Attributes::class)" - if both > of those === true, we import the attribute class and generate the needed > attributes for the command. Otherwise we would fall back to using > annotations if the user is running PHP 7. Where I ran into trouble was the > Attributes::class (defines the attributes to be used in userland) utilized > constructor property promotion (which is a pretty sweet addition to 8 imo). The way you write it here, there is no problem: you first check if the user is running PHP >= 8.0 (to see if you should use native attributes) and only if they are do you check if the Attributes class is available. > I would expect any of the \*_exists() to tell me if > the class/method/interface exists regardless of the implementation. As far as the PHP run-time is concerned, there is no definition of "exists" that doesn't involve an implementation. It might help to step through what actually happens in this case: * class_exists() first checks if the class is already defined; it's not, and you've left $autoload as true, so it calls the autoloader * the autoloader is just a callback function which is given the desired class name; generally, it translates that to a file name, and calls include/require * the autoloader asked PHP to include a particular file, so PHP tries to parse that file * as far as PHP 7.4 is concerned, the file contains a syntax error * since the file didn't compile, the class was never defined, so it continues to not exist Note that PHP 7.4 doesn't know that this is a PHP 8.0 class definition; it just sees it as invalid PHP. In the same way, a file containing the keyword "enum" has a syntax error under 8.0 but will be valid in 8.1; while one with typed properties has a syntax error under 7.3 but is valid from 7.4 onwards - I'm pretty sure I could come up with an example for every PHP release. > My first thought would be if the implementation is not compatible with the PHP > version some sort of \RuntimeException::class would be thrown by PHP. This is in fact exactly what happens: a ParseError is thrown, and can be caught like any other exception. However, I'm not clear what you'd do when you caught it, which is why I was hoping to see an example of the code you were actually trying to write. By far the most common solution to this problem is to mark the required PHP version at the package level: if you have files using PHP 8.0 syntax, the package containing them shouldn't be installed on a PHP 7.4 system. If they're not installed, the autoloader can't try to load them, and your class_exists() check will cleanly return false. If you do want to mix files for different PHP versions in one package, you could do it with a custom autoloader - e.g. all the PHP 8 only classes could be in a "src-php8" and the rest in "src"; the autoloader would check PHP_ VERSION_ID and simply ignore the "src-php8" directory for older versions. Again, the class_exists() check would cleanly return false. If you want to be able to generate PHP 8.0 code while running under PHP 7.4, then something like the library Marco linked to would seem to be the solution. Regards, -- Rowan Tommins [IMSoP]