Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:126027 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 546EC1A00BD for ; Thu, 21 Nov 2024 15:06:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1732201731; bh=NY4g3+QlS+roBHoVlpghslvgWDBbTCdyAJYuHbg2bIg=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=b/1LLydDGQLNf0cJdYxxbnEIRxf4E7W2ryQJsphT+59GhyrEdNOnGTTvZYh+IR+Sd 3tcfmqlOVMfEctKm7BYmI9+WBy8u5B6YvHEzO58p86BobSK3FB9Fk65nOSq8ekkJ2c zpKWz3rCRdyBHFCr8EjufJJO5a1YNeddxH//UCrYYgJf4cSAljW6pymfBO+tEPzsrn mpm6nx8mY9JoNlcMzGJ5GXBWzaRIVuOVG4528tFR6ASfUIrhWDeLETAQTu8s4rcP9T EheqfX4dW/FI7N2Cocn+gHqYI8Z1Q1d5FZr2b0Sbpkz/QEH0ri5fDETccNVF8SY4jB 9GcrA7CtQiucg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 1033418003F for ; Thu, 21 Nov 2024 15:08:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-oo1-f54.google.com (mail-oo1-f54.google.com [209.85.161.54]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 21 Nov 2024 15:08:49 +0000 (UTC) Received: by mail-oo1-f54.google.com with SMTP id 006d021491bc7-5ebc5b4190eso580755eaf.3 for ; Thu, 21 Nov 2024 07:06:09 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=melroseandco.uk; s=google; t=1732201568; x=1732806368; darn=lists.php.net; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=l5lGR1luLuQuiogtpJYe/waBHmwwslQj/4n4RebiP1U=; b=OR9zMBe08h0so7ZO1CwjcQ+BkQSZcyFQDtqL8aqz3wzx2F76qWe3/sUe4zWD0E/sT9 UDXHp9RAImLwc7wzbEDiXMUSFjKj/0RwXm6xq6hvFyIH8Rx/f6np/iA2hLCK0CZwAokk XeG3PsBABlTLzFP9KBdBKnfHi3CmagWyHuOHJroRau6YjjPlLLpmIZSJYzPGMnPgR7ue I154wOC5oZHmyNkBCYWZOeGYEUUub+8K1hhaiNDAMO3zVB7PgQlH/JoDk3FuenQ7LvE3 H3IfugfNE6ByKJ035ftN/UswMstlozpe/6xDc3DE5GuPDjGFF/oUFMe3EHaC12+77DKl hMYg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1732201568; x=1732806368; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=l5lGR1luLuQuiogtpJYe/waBHmwwslQj/4n4RebiP1U=; b=HW452thHP4+yZtODz2tTKuF8N9+iumUNvNJcVioVeF4ys1yHaBd3Yz5hwGHmnRhJsp eLLAlca88Z+X8mf9+nXHyM6fzxLws2grPHb7cEFj8Q90Nq/8ETqkLxUuDVc2ksylMOVx DuH1F14Q6Cstr2Ikh1pOGySK+DvqxzF5C4isPoMRJGUxhSTkNoACe5F/JNlPkyNfGkQE QGGNwJI3PRFPnJnXkHQ89fhFDZ9h+1E6Zdkv4vcOSyur1YeFUaQ+EQoTrkfDauBa/w3t BRM24YpnPxG9bF3xSIkW1YoTAZEqaANy0EBFfLMCisGxd6bwlE3f2HM+KtJmOlMa6sj0 sXdA== X-Gm-Message-State: AOJu0YwAOiinFe6Il7PE9Ee6gWj1OTQfqlBMQkKtzMR8Hm17aWlR29qo yL/t46YvNUY2fL/aualznipsNusVJmnO2tnttAFASY+KSlLmJI/MsmGcDla6WyeUoZyEzE6RvJD Mty4qrhkb3Y9pdDKhWRGvcapidCp1RovIWJayeg== X-Gm-Gg: ASbGncsqm3+lIAGcpGoHLFlGuYEURscgo1Y67ejs+iapxw8PileIWGbRijspKAlz+HH 9BMeOjPfOXa2VIgM2zHyVCSuBoqxsEg== X-Google-Smtp-Source: AGHT+IEvZLXmh9xUo2GdfCrrilMAmR6+OpHl4lQ0UIHZ3QsTRMILV7Vsrv+nKhcLZenc2hFwW17t704ZX4phMiOmb5s= X-Received: by 2002:a05:6359:7614:b0:1c3:7b75:24ec with SMTP id e5c5f4694b2df-1ca664a0c8fmr487839255d.15.1732201568533; Thu, 21 Nov 2024 07:06:08 -0800 (PST) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Thu, 21 Nov 2024 15:05:56 +0000 Message-ID: Subject: Re: [PHP-DEV] opcache_compile_file() declares top-level functions To: Ilija Tovilo Cc: PHP internals Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable From: sam@melroseandco.uk (Samuel Melrose) Thanks for reporting this Ilija, I came across the same problem when using `opcache_compile_file`, and agree it's confusing. For an example, please see the code sample in the opening comment of my PR: https://github.com/php/php-src/pull/16551 As part of my change to allow a read-only file based opcache, for use with Docker, I'm using `opcache_compile_file` on all files found with Symphony's Finder, although I had to force composer's autoloader not to load in the usual global scripts (i.e. that define helper functions), as I was getting the problem you describe around double declaration. I'd be very happy with your change to the behaviour, and if it lands in 8.5, it would hopefully complement my change which should have more people using `opcache_compile_file` with/in Docker container builds. Regards, Samuel Melrose On Wed, Nov 20, 2024 at 9:24=E2=80=AFPM Ilija Tovilo wrote: > > Hi everyone > > We recently received a bug report regarding the behavior of > opcache_compile_file() [1]. The documentation specifies: > > https://www.php.net/manual/en/function.opcache-compile-file.php > > > This function compiles a PHP script and adds it to the opcode cache wit= hout executing it. This can be used to prime the cache after a Web server r= estart by pre-caching files that will be included in later requests. > > Arguably, "without executing it" implies that, aside from putting the > script into opcache, there are no other observable side-effects. This > assumption is currently incorrect. To be more specific, > opcache_compile_file() differs from require in two ways: > > * The "main" function of the script (containing all the code at the > top-level) is not executed. > * Classes will not be added to the class table. > > Confusingly, top-level functions _will_ be added to the function > table. This has some weird consequences: > > * opcache_compile_file() can be called multiple times on files > containing classes. However, the same is not true for files containing > functions. The second call will lead to a function redeclaration > error. > > ```php > // index.php > opcache_compile_file(__DIR__ . '/test.php'); > opcache_compile_file(__DIR__ . '/test.php'); > > // test.php > class Foo {} // No problem > function foo() {} // Fatal error: Cannot redeclare function foo() > ``` > > * Similarly, after calling opcache_compile_file() on files containing > classes, the same file may later be required without issues. This does > not work for files containing functions for the same reason. > > ```php > // index.php > opcache_compile_file(__DIR__ . '/test.php'); > require __DIR__ . '/test.php'; > > // test.php > class Foo {} // No problem > function foo() {} // Fatal error: Cannot redeclare function foo() > ``` > > * Mixing functions with classes is incompatible. An attempt to use one > of the classes from one of the functions will either error because of > an undeclared class, or trigger the autoloader and include the file > again, leading to a function redeclaration error. > > ```php > // index.php > spl_autoload_register(function ($name) { > if ($name =3D=3D=3D 'Foo') { > require __DIR__ . '/b.php'; > } > }); > opcache_compile_file(__DIR__ . '/test.php'); > foo(); > > // test.php > class Foo {} > function foo() { > // Triggers the autoloader, the autoloader fails due to: > // Fatal error: Cannot redeclare function foo() > var_dump(new Foo()); > } > ``` > > * Functions that are conditionally declared will not be added to the > function table, since they are not top-level functions, even if the > condition always evaluates to true. > > ```php > // index.php > opcache_compile_file(__DIR__ . '/test.php'); > foo(); // Uncaught Error: Call to undefined function foo() > > // test.php > if (true) { > function foo() {} > } > ``` > > This behavior is inconsistent and confusing. Arguably, the correct > behavior is to never register functions in opcache_compile_file() to > begin with, since opcache_compile_file() exists to prime the cache, > rather than execute code. I created a PR with this change [2]. This is > breaking, since code using opcache_compile_file() might currently > depend on functions being declared and then calling them directly. > Such code would have to be adjusted to use require instead. > > Are there any concerns with making this change for 8.5? Are there any > use-cases this would break? > > Of note is that it may be beneficial to provide a related function > that allows compiling files and declaring symbols without executing > the "main" function. This could be useful static analysis tools that > want to reflect on files without executing them. That said, there are > existing solutions in userland that solve this problem in a better > way, like BetterReflection [3]. > > Ilija > > [1] https://github.com/php/php-src/issues/16668 > [2] https://github.com/php/php-src/pull/16862 > [3] https://github.com/Roave/BetterReflection