You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Weird behaviour when a file is autoloaded in assignment of a constant #10232
<?phperror_reporting(E_ALL);
ini_set('display_errors', 1);
class Loader
{
publicfunction__construct()
{
spl_autoload_register([$this, 'include'], true);
}
publicfunctioninclude()
{
require'test/constant.php';
}
}
newLoader();
class B
{
publicconstA = constant::TEST;
}
newB();
echo'here';
test/constant.php
<?phpdeclare(strict_types=1);
require_once'required.php';
class constant
{
publicconstTEST = 'test';
}
test/required.php
<?php
Resulted in this output:
Warning: require_once(required.php): Failed to open stream: No such file or directory in /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php on line 21 Call Stack: 0.0183 365472 1. {main}() /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php:0 0.1607 397352 2. Loader->include('constant') /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php:24 0.1611 397752 3. require_once('/mnt/fasterforward/web01/elements/src/httpdocs/test/test.php') /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php:11 Fatal error: Uncaught Error: Failed opening required 'required.php' (include_path='.:/usr/share/pear:/usr/share/php:/usr/share/pear:/usr/share/php') in /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php on line 21 Error: Failed opening required 'required.php' (include_path='.:/usr/share/pear:/usr/share/php:/usr/share/pear:/usr/share/php') in /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php on line 21 Call Stack: 0.0183 365472 1. {main}() /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php:0 0.1607 397352 2. Loader->include('constant') /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php:24 0.1611 397752 3. require_once('/mnt/fasterforward/web01/elements/src/httpdocs/test/test.php') /mnt/fasterforward/web01/elements/src/httpdocs/test/test.php:11
But I expected this output instead:
here
For some reason in when a file is autoloaded in assignment of a constant, the requires there do not get checked based on the location of that file.
When I put the autoloader outside of a class, require the file directly or specify constant as a type instead it works fine
In PHP 8.1.8 and PHP 7.4.30 with very simular php.ini's it works fine and the file gets required properly.
I thought it might be opcache but when I disable it the same problem happens.
I don't think this could ever have worked, unless you set include_path properly. You claim that constant.php and required.php are in the same directory, but the includes don't match that structure, and there is no chdir() happening.
So, have you set include_path for the other PHP versions? If not, which SAPI do you use? Is test.php really supposed to be a level above the other files, or actually stored in the same directory? And from which directory are you running the test (or what is the docroot, respectively).
I see I made a tiny mistake in the name of the file "test/required.php" just fixed that.
But yes test.php is in the location as indicated one level above the files included. And constant.php and required.php are in the same directory.
The include_path is not modified and is '.:/usr/share/pear:/usr/share/php:/usr/share/pear:/usr/share/php' for all versions.
The SAPI is "FPM/FastCGI' for all versions as well.
The docroot is ""/mnt/fasterforward/web01/elements/src/httpdocs/" in this case, made a seperate folder for testing called ``test` but you can replicate this behaviour from the command-line as well.
Reading through the documentation and seems that you are right it seems that requiring like this is not supposed to work, but it still does mostly work and did completely work for the previous versions.
I just tested it, and this behavior is working in a brand new installation of PHP 8.2.1 for windows.
If the file isn't found in the include_path, include will finally check in the calling script's own directory and the current working directory before failing.
And the issue is about a misidentification of the script's directory.
What I tried follows:
mkdir empty first second
cat <<'END' > main.php<?phpchdir(__DIR__ . '/empty');set_include_path(getcwd());spl_autoload_register(function () { require_once __DIR__ . '/second/SecondClass.php';}, true);$case = (int)$argv[1];require_once __DIR__ . '/first/FirstClass.php';new FirstClass();END
cat <<'END' > first/FirstClass.php<?phpif ($case == 1): // fails class FirstClass { public const VALUE = SecondClass::VALUE; }elseif ($case == 2): // fails class FirstClass { public $value = SecondClass::VALUE; }elseif ($case == 3): class FirstClass { public function __construct() { SecondClass::VALUE; } }elseif ($case == 4): class FirstClass {} SecondClass::VALUE;endif;END
cat <<'END' > second/SecondClass.php<?phprequire_once 'required.php'; // should load the file in the same directoryclass SecondClass { public const VALUE = 1; }END
cat <<'END' > required.php<?php echo basename(__DIR__), "\n";END
cp required.php first/
cp required.php second/
php82 main.php 1 # first
php82 main.php 2 # first
php82 main.php 3 # second
php82 main.php 4 # second
php81 main.php 1 # second
php81 main.php 2 # second
php81 main.php 3 # second
php81 main.php 4 # second
main.php explicitly loads FirstClass.php, which loads SecondClass.php by autoloading, and then SecondClass.php loads required.php. require_once 'required.php' in second/SecondClass.php should load second/required.php, but first/required.php is loaded on some cases with PHP 8.2.
Since EG(filename_override) set on constant resolution always takes precedence, require_once call on second/SecondClass.php is still resolved based on first/FirstClass.php's path.
Hi,
Yesterday faced with the same issue #13245
The behavior really changed, prior to 8.2 it works. We have a lot of code that uses it.
In doc it says that will firstly take a look in the directory of calling script and cwd (of course after include_path). But I think a lot of people are using that in this way like we did.
Activity
cmb69 commentedon Jan 5, 2023
I don't think this could ever have worked, unless you set
include_pathproperly. You claim that constant.php and required.php are in the same directory, but the includes don't match that structure, and there is nochdir()happening.So, have you set
include_pathfor the other PHP versions? If not, which SAPI do you use? Is test.php really supposed to be a level above the other files, or actually stored in the same directory? And from which directory are you running the test (or what is the docroot, respectively).fasterforward commentedon Jan 5, 2023
I see I made a tiny mistake in the name of the file "test/required.php" just fixed that.
But yes test.php is in the location as indicated one level above the files included. And constant.php and required.php are in the same directory.
The include_path is not modified and is '.:/usr/share/pear:/usr/share/php:/usr/share/pear:/usr/share/php' for all versions.
The SAPI is "FPM/FastCGI' for all versions as well.
The docroot is ""/mnt/fasterforward/web01/elements/src/httpdocs/" in this case, made a seperate folder for testing called ``test` but you can replicate this behaviour from the command-line as well.
Reading through the documentation and seems that you are right it seems that requiring like this is not supposed to work, but it still does mostly work and did completely work for the previous versions.
I just tested it, and this behavior is working in a brand new installation of PHP 8.2.1 for windows.
fasterforward commentedon Jan 13, 2023
Retested this bug on PHP 8.2.1. with FPM/FastCGI and Oracle Linux 8 same result
ranvis commentedon Jan 16, 2023
I think I have confirmed the issue on PHP 8.2.1 CLI.
From the document of include():
And the issue is about a misidentification of the script's directory.
What I tried follows:
main.php explicitly loads FirstClass.php, which loads SecondClass.php by autoloading, and then SecondClass.php loads required.php.
require_once 'required.php'in second/SecondClass.php should load second/required.php, but first/required.php is loaded on some cases with PHP 8.2.ranvis commentedon Jan 28, 2023
Since
EG(filename_override)set on constant resolution always takes precedence,require_oncecall onsecond/SecondClass.phpis still resolved based onfirst/FirstClass.php's path.php-src/Zend/zend_execute_API.c
Lines 609 to 614 in 479b47c
I guess error reporting and path resolution should be differentiated here.FuZuK commentedon Jan 26, 2024
Hi,
Yesterday faced with the same issue #13245
The behavior really changed, prior to 8.2 it works. We have a lot of code that uses it.
In doc it says that will firstly take a look in the directory of calling script and cwd (of course after include_path). But I think a lot of people are using that in this way like we did.
Temporary reset filename and lineno override before autoload