[php-src] Issue #13245: require_once throws the exception when try to load file from script directory during autoloading
| From: | FuZuK | Date: | Thu, 25 Jan 2024 20:25:01 +0000 |
| Subject: | [php-src] Issue #13245: require_once throws the exception when try to load file from script directory during autoloading | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-246342@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/13245
Author: FuZuK
### Description
The following code:
file: test.php
```php
<?php
spl_autoload_register(function ($class_name) {
if (class_exists($class_name)) {
return true;
}
$class_sources = [
__DIR__ . '/src',
];
$class_name = trim($class_name, '\\');
$file = str_replace('\\', DIRECTORY_SEPARATOR, $class_name) . '.php';
foreach ($class_sources as $source) {
$class_path = $source . DIRECTORY_SEPARATOR . $file;
if (is_file($class_path)) {
require_once $class_path;
return true;
}
}
return false;
});
echo 'PHP version: ' . phpversion() . PHP_EOL;
print_r((new Product)->getStatuses());
```
file: src/Product.php
```php
<?php
class Product
{
protected array $statuses = [
'disabled' => ProductStatus::DISABLED,
'enabled' => ProductStatus::ENABLED,
];
public function getStatuses()
{
return $this->statuses;
}
}
```
file: src/ProductStatus.php
```php
<?php
require_once __DIR__ . '/../Exception/ProductException.php';
class ProductStatus
{
const ENABLED = 1;
const DISABLED = 0;
const TIMEOUT = 5;
}
```
file: Exception/ProductException.php
```php
<?php
require_once('BaseException.php');
class ProductException extends BaseException {}
```
file: Exception/BaseException.php
```php
<?php
class BaseException extends Exception {}
```
Resulted in this output:
```
PHP version: 8.2.15
PHP Warning: require_once(BaseException.php): Failed to open stream: No such file or directory in
/app/src/Product.php on line 6
PHP Fatal error: Uncaught Error: Failed opening required 'BaseException.php'
(include_path='.:/usr/share/php') in /app/src/Product.php:6
Stack trace:
#0 /app/src/ProductStatus.php(3): require_once()
#1 /app/test.php(19): require_once('...')
#2 /app/test.php(29): {closure}()
#3 {main}
thrown in /app/src/Product.php on line 6
```
But I expected this output instead:
```
PHP version: 8.2.15
Array
(
[disabled] => 0
[enabled] => 1
)
```
Prior to PHP 8.2 it works fine.
PHP 8.1.27:
```
PHP version: 8.1.27
Array
(
[disabled] => 0
[enabled] => 1
)
```
PHP 7.4.33:
```
PHP version: 7.4.33
Array
(
[disabled] => 0
[enabled] => 1
)
```
It relates not only to require_once, other include/require functions execute with the same result.
I've discovered the UPGRADING notes, but did not find any points about that something has been
changed in include/include_once/require/require_once behavior. The solution for this case is to use
__DIR__ in Exception/ProductException.php, but wanna to know the reason why it executes
unexpectedly.
Possibly that's because it's loading via class autoloader, because if to avoid the use of
autoloader and include files src/Product.php and src/ProductStatus.php directly in test.php, it
works fine.
Dockerfile used for test:
```
FROM debian:bullseye-slim
WORKDIR /app
RUN apt update
RUN apt -y install lsb-release apt-transport-https ca-certificates wget vim nano less curl gnupg2
RUN wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
RUN echo "deb https://packages.sury.org/php/
$(lsb_release -sc) main" | tee /etc/apt/sources.list.d/php.list
RUN apt update
RUN apt install -y php8.2-cli php8.2-common php8.2-mbstring php8.2-dba php8.2-gd php8.2-gnupg
php8.2-igbinary php8.2-imagick php8.2-imap php8.2-bcmath php8.2-ldap php8.2-bz2 php8.2-dom
php8.2-mysql php8.2-opcache php8.2-pgsql php8.2-curl php8.2-memcached php8.2-msgpack php8.2-readline
php8.2-redis php8.2-soap php8.2-ssh2 php8.2-xml php8.2-xmlrpc php8.2-zip php8.2-maxminddb
php8.2-intl php8.2-stomp
RUN rm -rf /var/lib/apt/lists/* /var/cache/debconf && apt-get clean
ENTRYPOINT [ "/bin/bash" ]
```
Command to run:
```bash
# build
docker build -f Dockerfile -t php8.2-cli:dev --no-cache ./
# run
docker run --rm -ti -v "$(pwd):/app" php8.2-cli:dev -c 'php test.php'
```
### PHP Version
PHP 8.2.15
### Operating System
Debian 11