php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #40875 Circular require_once causes fatal error
Submitted: 2007-03-21 00:46 UTC Modified: 2007-03-21 05:53 UTC
From: epotocko at gmail dot com Assigned:
Status: Not a bug Package: Compile Failure
PHP Version: 5.2.1 OS: Windows XP Pro
Private report: No CVE-ID: None
 [2007-03-21 00:46 UTC] epotocko at gmail dot com
Description:
------------
A circular reference between three files is causing a fatal error.

The simplest example I could reproduce this with is:
B extends A
C extends B
B uses D
D uses C

If class B is modified so that it does not extend class A, the error does not occur.

Reproduce code:
---------------
ClassA.php:
<?php
class ClassA {}
?>

ClassB.php:
<?php
require_once('ClassA.php');
require_once('ClassD.php');
class ClassB extends ClassA {}
?>

ClassC.php
<?php
require_once('ClassB.php');
class ClassC extends ClassB {}
?>

ClassD.php
<?php
require_once('ClassC.php');
class ClassD {}
?>

test.php
<?php
require_once('ClassB.php');
?>

Expected result:
----------------
If you execute test.php no errors should occur.

Actual result:
--------------
PHP Fatal error: Class 'ClassB' not found in ClassC.php on line 3


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-03-21 00:47 UTC] epotocko at gmail dot com
I can also reproduce this in Linux with PHP 5.1.6
 [2007-03-21 05:53 UTC] cellog@php.net
Unfortunately, this is expected behavior.

Here is the logic path:

test.php => require_once classB.php
   classB.php required yet? no
classB.php => require_once classA.php
   classA.php required yet? no
classA.php => declare class A
classB.php => require_once classD.php
   classD.php required yet? no
classD.php => require_once classC.php
   classC.php required yet? no
classC.php => require_once classB.php
   classB.php required yet? YES, SKIP
classC extends ClassB => fatal error, classB doesn't exist.

There is a way around this, and it is to re-design your classes so 
they don't have such a complex relationship, or to re-order your 
require_once statements.  PHP can't be changed, as the parse order 
always requires parsing included files first in order to grab 
dependencies (parent classes), and so these are processed before the 
class declaration is even parsed.  Otherwise the simplest example of 
having two classes in separate files would fail.

For instance, if you were to place
require_once 'ClassD.php' after the classB declaration:

<?php
require_once 'ClassA.php';
class ClassB extends ClassA {}
require_once 'ClassD.php';
?>

your code sample will work.  Incidentally, PEAR makes use of this 
exact technique in order to handle complex inter-relationships.  
PEAR/Config.php has require_once statements at the end of the file 
after PEAR_Config class is created.

not a PHP bug => bogus.
 [2015-07-07 15:45 UTC] lemsan dot inc at gmail dot com
Hi,

Actually something doesn't agree in the logic path in the case "extends ClassA" is removed in ClassB.php. The code is working in this case, though following the logic you described, it should fail.
 [2015-07-07 15:45 UTC] lemsan dot inc at gmail dot com
Hi,

Actually something doesn't agree in the logic path in the case "extends ClassA" is removed in ClassB.php. The code is working in this case, though following the logic you described, it should fail.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 07:01:28 2024 UTC