[php-src] Issue #11466: Class Incorrectly Labeled as Not Available
| From: | Zykaris | Date: | Fri, 16 Jun 2023 19:18:12 +0000 |
| Subject: | [php-src] Issue #11466: Class Incorrectly Labeled as Not Available | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-244715@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/11466
Author: Zykaris
### Description
I have been under the impression that PHP doesn't require forward-declarations; however, the
following code results in a "class not available" fatal error, even though all classes are
present:
```php
<?php
// infant.php
class Infant
{
public int $health = 0;
public string $name = "";
}
interface Fertile
{
function spawn() : Infant;
}
?>
```
```php
<?php
// main.php
require_once "infant.php";
class Zergling implements Fertile
{
public function spawn() : Infantling
{
return new Infantling();
}
}
class Infantling extends Infant
{
}
print_r(new Zergling());
?>
```
```shell
php -f main.php
```
Resulted in this output:
```
Fatal error: Could not check compatibility between Zergling::spawn(): Infantling and
Fertile::spawn(): Infant, because class Infantling is not available main.php on line 6
```
But I expected this output instead:
```
Zergling Object
(
)
```
This single-file version also produces the same error (using a strange pattern of declarations, I
know, but I thought it didn't matter):
```php
<?php
class Zergling implements Fertile
{
public function spawn() : Infantling
{
return new Infantling();
}
}
class Infantling extends Infant
{
}
class Infant
{
public int $health = 0;
public string $name = "";
}
interface Fertile
{
function spawn() : Infant;
}
print_r(new Zergling());
?>
```
There are two ways around this error. First, the code from "infant.php" can be manually
placed at the top of "main.php" (replacing the require_once statement)--note that this
works even though Infantling is still declared after Zergling, as expected of PHP:
```php
<?php
class Infant
{
public int $health = 0;
public string $name = "";
}
interface Fertile
{
function spawn() : Infant;
}
class Zergling implements Fertile
{
public function spawn() : Infantling
{
return new Infantling();
}
}
class Infantling extends Infant
{
}
print_r(new Zergling());
?>
```
Second, declare (or--more accurately--define) Infantling above Zergling:
```php
<?php
require_once "infant.php";
class Infantling extends Infant
{
}
class Zergling implements Fertile
{
public function spawn() : Infantling
{
return new Infantling();
}
}
print_r(new Zergling());
?>
```
This last work-around is the simplest--and is what I have been using when this sort of issue
arises--but this is an annoying inconsistency. Shouldn't a class either never need to be
declared prior to usage (as long as it's included/declared somewhere in the file), or always
need to be declared before usage (in which case forward-declarations would be welcome in order to
allow freedom in file formatting)? I was under the impression that the former was the case with PHP,
but am I mistaken, or is this really a bug?
_Note: I believe this problem has been around since PHP 7 (at least). I just finally decided to
mention it now._
### PHP Version
PHP 8.2.7
### Operating System
Windows 11