Bug #78124 [Opn->Wfx]: Subclass of an included class not available
| From: | cmb@php.net | Date: | Mon, 15 Mar 2021 15:45:18 +0000 |
| Subject: | Bug #78124 [Opn->Wfx]: Subclass of an included class not available | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-232736@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78124&edit=1
ID: 78124
Updated by: cmb@php.net
Reported by: aschmidt at anamera dot net
Summary: Subclass of an included class not available
-Status: Open
+Status: Wont fix
Type: Bug
Package: Scripting Engine problem
Operating System: Win x64
PHP Version: 7.2.19
-Assigned To:
+Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
The VLD output[1] hints at what's happening. The point is that
PHP first compiles a file, and runs it afterwards. When it
compiles the main script, myClass1 and mySubClass1 are fully
defined, and so can be linked. However, mySubClass2 cannot be
linked, because myParentClass is not yet known. Then the main
script is run, starting with including the file where
myParentClass is defined; then the script proceeds to the first
var_dump() where mySubClass2 is still not defined, because it is
only linked afterwards (see the ADD_INTERFACE opcode). For the
second var_dump(), all classes are defined.
Well, bug or not a bug? Let's say wont-fix. That is just how PHP
works.
The best *general* advice to never face these kinds of issues is
to never mix declarations and execution logic[2]. And then rely
on autoloading, to avoid loading classes you don't need.
> With OPcache running, the entire script appears not be parsed
> unless I remove the "return;".
I presume you're hitting OPcache's optimizer's dead code elimination
here. The code after the
return is never supposed to be executed,
so isn't even compiled (practically). I think you can deactivate
DCE with
opcache.optimization_level=0x7FFE9FFF
[1] <https://3v4l.org/GnDr2/vld#output>
[2] <https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md#23-side-effects>
Previous Comments:
------------------------------------------------------------------------
[2019-06-09 12:54:11] aschmidt at anamera dot net
Thanks for that test. So in my attempt to strip down the code of my (possibly SECONDARY problem) to
the bare essentials, I unintentionally may have stumbled on the the more generic, primary problem?
Now that it's reproduced in all PHP releases, is this accepted as an unintended behavior/bug?
PS: My ORIGINAL problem occurs in a complex application (a Plug-In file in a WordPress environment),
where the "test script" code itself is part of a deep multi-level code and include
sequence in WordPress.
In my "real" problem, the code that is unable to reference the subclass (demonstrated by
the "class_exists(...);") is actually inside a function that gets called much later by
WordPress in its execution order. Lucky for me in that combination, the PHP parser will have already
parsed the entire script (including subclass that extends an included class) before the function is
ever called, effectively MASKING the above problem.
But, my production code has a "return;" statement BEFORE the subclass definition. I have
the suspicion that given the primary problem you reproduced, there is then a secondary problem when
OPcache is running: With OPcache running, the entire script appears not be parsed unless I remove
the "return;". That then UNmasks the primary problem of extending parent classes that
reside in includes.
------------------------------------------------------------------------
[2019-06-08 09:22:05] sjon@php.net
this behavior seems pretty consistent: https://3v4l.org/GnDr2
------------------------------------------------------------------------
[2019-06-07 19:51:22] aschmidt at anamera dot net
I had ASSUMED that to be the case.
But then I reproduced the problem even after I updated the PHP.INI to comment out all caching
includes, and restarting the web server:
;zend_extension=php_opcache.dll
[XDebug]
; Must be loaded after OpCache !
;zend_extension = "C:\Program Files\PHP\v7.2\ext\php_xdebug-2.7.2-7.2-vc15-nts-x86_64.dll"
xdebug.coverage_enable=0
[PHP_WINCACHE]
;extension=php_wincache.dll
------------------------------------------------------------------------
[2019-06-07 19:27:00] nikic@php.net
You likely have opcache enabled on one version and disabled on the other. Is that the case?
------------------------------------------------------------------------
[2019-06-07 19:02:23] aschmidt at anamera dot net
Description:
------------
If a class extends a parent class from an include/require, then the subclass cannot be referenced
until AFTER the class definition.
However, if a class extends a parent class from the SAME script, then the subclass CAN be referenced
anywhere in the code.
I can't tell at what point this broke, but this appears to have worked in earlier 7.2 releases.
Test script:
---------------
<?php
declare(strict_types=1);
require( 'bug2.php' );
// Error: mySubClass2 does NOT exist!
var_dump( class_exists( 'myClass1', FALSE ), class_exists( 'mySubClass1', FALSE
), class_exists( 'myParentClass', FALSE ), class_exists( 'mySubClass2', FALSE )
);
class myClass1 {
const myConst = 'C1';
}
class mySubClass1 extends myClass1 {
const myConst = 'S1';
}
class mySubClass2 extends myParentClass {
const myConst = 'S2';
}
// Correct: Now mySubClass2 DOES exist!
var_dump( class_exists( 'myClass1', FALSE ), class_exists( 'mySubClass1', FALSE
), class_exists( 'myParentClass', FALSE ), class_exists( 'mySubClass2', FALSE )
);
Content of file "bug2.php":
<?php
declare(strict_types=1);
class myParentClass {
const myConst = 'Parent';
}
Expected result:
----------------
subclass_bug.php:7:boolean true
subclass_bug.php:7:boolean true
subclass_bug.php:7:boolean true
subclass_bug.php:7:boolean true
Actual result:
--------------
subclass_bug.php:7:boolean true
subclass_bug.php:7:boolean true
subclass_bug.php:7:boolean true
subclass_bug.php:7:boolean false
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78124&edit=1