PHP - require_once和类继承问题

I get a fatal error: Fatal error: Class 'Foo1' not found in .../Foo2.php on line 5 with the following files:

index.php:

<?php
require_once("./Foo1.php");
?>
<h1>Success</h1>

Foo1.php:

<?php
require_once('./IFoo.php');
require_once('./Bar.php');

class Foo1 implements IFoo
{
    /** @var  Bar */
    private $bar;
}

IFoo.php:

<?php
interface IFoo {
}

Bar.php:

<?php
require_once('./Foo2.php');

class Bar {
    /** @var  Foo2 */
    private $foo;
}

Foo2.php:

<?php
require_once("./Foo1.php");

class Foo2 extends Foo1
{
}

Questions:

  1. How to solve this situation?
  2. Why when I suppress the implements IFoo statements, this code works?

Update Most of the solutions proposed, involved autoloading. Unfortunately, my problem is on a old project with a lot of existing code and a lot of bad practice. We are really far from PSR-0 standard.

What is the cost of introducing autoloading in terms of performances?

I suggest to use Autoloading Standard PSR-0. It describes the mandatory requirements that must be adhered to for autoloader interoperability.

Anyway in this case:

Foo1.php

You are including Bar.php and because of this line: require_once('./Foo2.php');, Class Foo2 extends Class Foo1. But Class Foo1 is not defined yet! You can extend a class only after It's definition.

So It seems that require_once('./Foo2.php'); not should be in Bar.php. Or You should move require_once('./Bar.php'); after class Foo1 definition.

<?php
require_once('./IFoo.php');

class Foo1 implements IFoo
{
    /** @var  Bar */
    private $bar;
}

require_once('./Bar.php');

If you modify Foo1.php file to this

<?php
require_once('./IFoo.php');

class Foo1 implements IFoo
{
/** @var  Bar */
private $bar;
}

require_once('./Bar.php');

?>

This works.

The reason is PHP is interpreted language (interpreter executes the script line by line). So, in your case interpreter misses the Foo1 declaration statement and raises an error when it encounters an undefined class Foo1 in Foo2.php.

  1. Use autoloading feature. Do not any any other executable code (like require / include) in file with class definition.
  2. Because when Foo1 implements IFoo, php does not know anything about IFoo, so it can not register class Foo1. since no autoloader is registered, php starts to interpret the code with, omitting class declaration from Foo1.php, until other files are included and parsed. When it reaches Foo2.php it is not including Foo1.php (due to require_once) and starts interpreting the file - here it encounters class Foo1 that's definition was skipped due to non-existant at that time interface implementation. At this point php has no idea that Foo1 was declared in already required Foo1.php, since it hadn't got a chance to intepret this file wholly.