php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #75943 autoload trying load existing class when it extends not existing class
Submitted: 2018-02-09 08:22 UTC Modified: 2018-02-09 14:19 UTC
From: akademic at hub dot sknt dot ru Assigned:
Status: Suspended Package: Class/Object related
PHP Version: 7.2.2 OS: Ubuntu 16.04.3 LTS
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2018-02-09 08:22 UTC] akademic at hub dot sknt dot ru
Description:
------------
In example below I expect that autoload call back will try to load class_two.
But it try to load existing class_one.

If you comment out 'extends class_two', autoload callback will not start.


Test script:
---------------
spl_autoload_register(function($class) {
    var_dump('autoload '.$class);
});

test();

function test() {
    $m = new class_one();
}

class class_one extends class_two {
    function __construct() {
        var_dump('I am '.__CLASS__);
    }
}

Expected result:
----------------
string(18) "autoload class_two"

Actual result:
--------------
string(18) "autoload class_one"

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-02-09 08:42 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2018-02-09 08:42 UTC] requinix@php.net
You've encountered an edge case when it comes to defining classes after they're used.

PHP runs files in two steps: a compilation phase where it tries to understand what's in a file, and an execution phase where it actually runs the code. If a class can be fully understood during the first phase then you can use it at any place in the file regardless of whether it comes before or after the definition, but if not then class definition has to be "executed" during the second phase.

Since class_two is not defined, class_one cannot be loaded during the first phase. In the second phase, since test() executes before the class_one definition, PHP will not know the class exists yet and thus will try to autoload it.

If you want PHP to try to autoload class_two then class_one has to be defined before test() tries to use it.
https://3v4l.org/Ei3Ek
 [2018-02-09 12:26 UTC] akademic at hub dot sknt dot ru
This is so different behavior in almost the same situation.
This is extreamly confusing. 
Imagine that you've just written class and it works.
Than you refactor your class and move some functions in parent.
Now all things are broken. And you can't undestand why.

I believe this need to be fixed in PHP.
 [2018-02-09 12:43 UTC] requinix@php.net
Think about this.
1. PHP cannot have class_one defined without knowing what class_two is, right? Obviously.
2. If class_two does not exist when the file is compiled then class_one cannot be available yet when it's done.
3. So when PHP starts executing the file, class_one does not exist. It will be only when those lines of code execute.
4. If you try to use class_one before those lines of code get executed then PHP will do what it's supposed to do and call the autoloader.

Do you think that this code should work?
  echo $x;
  $x = 1;

Yeah, refactoring your code has given you more work to do. Welcome to the world of software development.
 [2018-02-09 12:58 UTC] spam2 at rhsoft dot net
> edge case when it comes to defining classes after they're used

there are a lot of more edge-cases like https://bugs.php.net/bug.php?id=75542 where obviously opcache takes over way to much of what the compiler should do

"PHP runs files in two steps: a compilation phase where it tries to understand what's in a file" is skipped in the bugreport above and we talk about just a single file
 [2018-02-09 13:10 UTC] requinix@php.net
As far as I'm concerned, the bug in your report is that the code works with opcache, not that it doesn't without.
Frankly I wish we could get rid of the whole "functions/classes can be used before they're defined" feature.
 [2018-02-09 13:14 UTC] spam2 at rhsoft dot net
no, the bug is clearly that it don't work without because at *compile time* there is no reason that order matters - that's what compilers are about

the *real* problem anyways is that it behaves different at all while a cache/optimizer should be fully transparent and not change basic behavior
 [2018-02-09 13:20 UTC] akademic at hub dot sknt dot ru
I've understood your first comment completly.
And now I know what happens under the rug. And I've fixed my code now.
I appreciate your help.

Your example (`echo $x; $x = 1;`) is about _execution_.
My example (`class class_one extends class_two`) is about _declaration_. I believe there is the difference.

I understand technical reasons.
But take a look on this case from PHP-user point.

I have a class:
`class class_one {}`

And it works perfectly.

Now I change it to `class class_one extends class_two {}`
My thoughts: I don't have class_two in this file, but I have autoload function, which knows where class_two is located. So that's ok.

Reality: Fatal error: Class 'class_one' not found. WTF?

I haven't changed the names. I haven't moved code blocks around. I've simply added a little bit of inheritance and things have gone wrong.

It shouldn't be that. Both situations (with and without inheritance) should fail or both situations should success.
 [2018-02-09 13:40 UTC] requinix@php.net
> the *real* problem anyways is that it behaves different at all
Of course. I was addressing the (unasked) question of which of the two behaviors was correct. You say one, I say the other. But it's ultimately about opcache, which I am certainly not an expert of.

> Your example is about _execution_. My example is about _declaration_.
At first glance yes, because as PHP developers we have the ingrained belief that class and function definitions are separate from the execution of the script. But that is not entirely true. Sometimes there is overlap. This is one of those times.

I think I've made my point clear enough that I can't really add anything more to it, so unless a dev comes and says I'm incorrect then this report is not a bug and is simply a misunderstanding of some of the PHP internals. These sorts of things are often hidden to userland developers anyways.

Unless you want to make this a feature request. Do you believe that PHP should change how it deals with classes (and functions) to suit your needs?
 [2018-02-09 13:43 UTC] requinix@php.net
Oh. I missed out on this reply:

> Your example (`echo $x; $x = 1;`) is about _execution_.
"No, I say that $x=1 is a declaration. I'm declaring $x to be a variable with the initial value of 1. PHP should recognize this and allow me to use the variable in the echo statement, and the fact that it does not is a bug."

Tomato, tomato.
 [2018-02-09 14:14 UTC] akademic at hub dot sknt dot ru
> Oh. I missed out on this reply:
Oh, come on. :) I see you've understand what I've meant.

I believe that this issue should become PHP improvement.
Like it was with supporting expressions in empty() function, late static binding and so on.

If PHP could find class_one in current file, PHP would become more smooth language. It's not about my needs, it's about consistency.
 [2018-02-09 14:19 UTC] requinix@php.net
-Status: Not a bug +Status: Suspended -Type: Bug +Type: Feature/Change Request
 [2018-02-09 14:19 UTC] requinix@php.net
Thank you for your interest in PHP and for submitting a feature
request. Please be aware that due to the magnitude of change this
request requires, it would be necessary to discuss it on PHP
Internals list (internals@lists.php.net) as an RFC. Please read
the guide about creating RFCs here:
<https://wiki.php.net/rfc/howto>. If you haven't had experience
with writing RFCs before, it is advised to seek guidance on the
Internals list (<http://php.net/mailing-lists.php>) and/or solicit
help from one of the experienced developers.

Please something something this comment something a view on the
merits of your proposal – every proposal which requires changes of
certain magnitude, even the very successful and widely supported
ones, must be done through the RFC process. This helps make the
process predictable, transparent and accessible to all developers.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 12:01:27 2024 UTC