php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79022 class_exists returns True for classes that are not ready to be used
Submitted: 2019-12-23 22:24 UTC Modified: -
From: mech at themech dot net Assigned:
Status: Closed Package: *General Issues
PHP Version: 7.4.1 OS: Linux
Private report: No CVE-ID: None
 [2019-12-23 22:24 UTC] mech at themech dot net
Description:
------------
I noticed this issue while debugging Koseven framework with PHP 7.4. It is related to class autoloading.
Imagine there is an autoloader function registered with the following code inside:
if (class_exists('B', False)) {
   new B();
}
If class B extends some other class A and autoloading function is called to load class A then class_exists('B', false) returns true even if B is not "fully loaded" as its parent class A is still to be loaded. So under PHP 7.4 the "new B()" is being executed and throws "Fatal error: Uncaught Error: Class 'B' not found".
The same code works with PHP 7.3


Test script:
---------------
<?php
// classes/Foo.php: class Foo extends Bar {}
// classes/Bar.php: class Bar {} 
function my_autoloader($class) {
    if (class_exists('Foo', False)) {
	new Foo();
    }
    if ($class == 'Foo' or $class == 'Bar') {
		include "classes/$class.php";
    }
}
spl_autoload_register('my_autoloader');
new Foo();
echo "end"

Expected result:
----------------
class_exists should not return true for the class that does not exist yet.atal

Actual result:
--------------
Fatal error, class not found.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2019-12-24 06:25 UTC] laruence@php.net
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=153c9cc346bae927394d3ce1378f77fb7c1e1be3
Log: Fixed bug #79022 (class_exists returns True for classes that are not ready to be used)
 [2019-12-24 06:25 UTC] laruence@php.net
-Status: Open +Status: Closed
 [2019-12-24 06:27 UTC] laruence@php.net
Automatic comment on behalf of laruence@gmail.com
Revision: http://git.php.net/?p=php-src.git;a=commit;h=153c9cc346bae927394d3ce1378f77fb7c1e1be3
Log: Fixed bug #79022 (class_exists returns True for classes that are not ready to be used)
 [2020-02-11 10:07 UTC] raj0chaturvedi at gmail dot com
> gc '.\test script.php'
<?php
function my_autoloader($class) {
    if (class_exists('Foo', False)) {
                new Foo();
    }
        if ($class == 'Foo' or $class == 'Bar') {
        include_once "classes/$class.php";
    }
}
spl_autoload_register('my_autoloader');
new Foo();
echo "end";
---
---


> gci | ft FullName                                                                      
FullName
--------
D:\repro bug 79022\classes
D:\repro bug 79022\test script.php

---
---

> gc .\classes\Bar.php
<?php
class Bar {}
> gc .\classes\Foo.php                                                                                
<?php
include_once "Bar.php";
class Foo extends Bar {}

---
---

works for me on Windows 10 1909. with above code and files.
tested by typing
>php.exe "test script.php"
and
>php.exe -f "test script.php"

> php -v
PHP 7.4.2 (cli) (built: Jan 21 2020 17:53:48) ( ZTS Visual C++ 2017 x86 )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies


about comment formatting: I don't know how to format it. See https://pastebin.com/QHzw60Dg for colored output. the paste expires in 364 days. to see raw paste content https://pastebin.com/raw/QHzw60Dg

---
---

aside:

To repeat a message I thought was unexpected uncomment the include_once "Bar.php" line in Foo.php file. Then type
> php .\classes\Foo.php
PHP Fatal error:  Uncaught Error: Class 'Bar' not found in D:\repro bug 79022\classes\Foo.php:4
Stack trace:
#0 {main}
  thrown in D:\repro bug 79022\classes\Foo.php on line 4
Fatal error: Uncaught Error: Class 'Bar' not found in D:\repro bug 79022\classes\Foo.php:4
Stack trace:
#0 {main}
  thrown in D:\repro bug 79022\classes\Foo.php on line 4

It is a bit weird that the exact same error is printed twice. And now, more weird stuff, note the include-once line is commented.

> php -f '.\test script.php'
end
> php.exe -f .\classes\Bar.php
> php.exe -f .\classes\Bar.php

I think it's weird that the first command prints end and nothing else. When compared to how 'php -f Foo.php' is handled.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Dec 03 17:01:29 2024 UTC