2

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?

Alban Soupper
  • 671
  • 1
  • 5
  • 20

3 Answers3

1

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.

R Simon
  • 183
  • 1
  • 13
  • Interesting proposition... would it mean that the best way to manage the includes are first the parents or interfaces that the class will implements. And after the class, include the other classes used at runtime? – Alban Soupper Sep 09 '13 at 08:24
1
  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.
dev-null-dweller
  • 29,274
  • 3
  • 65
  • 85
  • 1. _autoloading_ could be a solution but I am a little hesitant to introduce its use because I don't know the performance impact. 2. "Because when Foo1 implements IFoo, php does not know anything about IFoo" - I don't understand because in Foo1.php the first thing included is IFoo... – Alban Soupper Sep 09 '13 at 08:19
  • It is included but not parsed, because it implements unknown interface, so instead of registering known class, it is executing file line by line, steping deeper into `require_once`. As for performance, [there is no reason not to autoload](http://blog.ircmaxell.com/2012/07/is-autoloading-good-solution.html) – dev-null-dweller Sep 09 '13 at 09:40
0

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');
Vahid Hallaji
  • 7,159
  • 5
  • 42
  • 51
  • Thanks for these two propositions. Please see my question update. So if I don't want to use autoloading, the solution would be to import first the classes needed for classes declaration. and after the implementation, include the others classes need at runtime...? – Alban Soupper Sep 09 '13 at 08:22
  • @AlbanSoupper if you don't want to use autoloading, What you exactly care about it is: Do not extend or Do not create new instance of class before it's definition. Because of `php` Interpret scripts line by line. – Vahid Hallaji Sep 09 '13 at 08:34
  • @AlbanSoupper Define each `Class` or `Interface` in a separate file and `require_once` only needed interfaces or classes for current class. It helps you a lot. – Vahid Hallaji Sep 09 '13 at 08:46