0

I have two files, let's say a.php and b.php:

a.php:

require 'b.php';
interface testInterface{}
class a implements testInterface{}

b.php:

class b extends a{}

When I run a.php, it throws this fatal error:

Fatal error: Class 'a' not found in b.php on line 2

Two considerations that make it more interesting:

  • Everything works fine if I remove the implements clause in the class a.

  • Everything works fine if I put the class b in the same file as class a, without including it as an external file.

I can't understand why it's throwing that error, any help really appreciated.

iainn
  • 16,826
  • 9
  • 33
  • 40
T30
  • 11,422
  • 7
  • 53
  • 57
  • 2
    You require b.php, which relies on the definition of `class a`, before you define `class a`. For {reasons} it happens to work without the interface, but you should not be creating this logical carousel in the first place. – deceze Dec 14 '17 at 11:41
  • did you require a.php as well? – meewog Dec 14 '17 at 11:41
  • @MehrdadDastgir I'm running a.php directly – T30 Dec 14 '17 at 11:42
  • 3
    Why is the file defining the *parent class* also importing the file with the *child class*?! Parents should not know about their children. b.php should `require_once 'a.php'` and you should be executing b.php. – deceze Dec 14 '17 at 11:44
  • 1
    learn to use autoloading – tereško Dec 14 '17 at 11:46
  • 1
    @deceze I wanted to instantiate b from a, but now I realize that's not how it should work. Thanks. – T30 Dec 14 '17 at 11:55

3 Answers3

2

Edit: On the off-chance that anyone else comes across this, I just stumbled across this answer that does a far better job of explaining things: Why can't you inherit from a not-yet-defined class which inherits from a not-yet-defined class?

The separate files aspect of this is actually irrelevant - you can reproduce the same behaviour by simply defining the classes/interfaces out of order.

I don't know nearly enough about PHP's internals to say why any of this happens, but if there is anything more than a very simple inheritance structure, then the classes need to be defined in order.

This works:

<?php
class b extends a {}
class a {}

This does not:

<?php
class c extends b {}
class b extends a {}
class a {}

You can cause similar weirdness when implementing interfaces, as in your question:

Works:

<?php
interface testInterface {}
class b extends a implements testInterface {}
class a {}

Doesn't work:

<?php
interface testInterface {}
class b extends a {}
class a implements testInterface {}

In short: Always declare your interfaces, classes and traits in the order in which they're used. PHP might be able to figure things out for you, but don't rely on it (and I suspect different versions will also behave in subtly different ways). The same conclusion was reached in this question, posted a few years ago by Taylor Otwell, of all people.

iainn
  • 16,826
  • 9
  • 33
  • 40
1

Put require 'b.php'; at last. class a should be declared before class b

interface testInterface{}
class a implements testInterface{}
require 'b.php';
freelancer
  • 1,174
  • 5
  • 12
-1

In class b you are inheriting class, and you are declaring class a after the class b is included. PHP runs top to bottom. When it includes b.php then it try to execute the code written in b.php, But at this point class a is not declared. That is why it is throwing a fatal error and stopping the further execution.

Try including the b.php after the class a is declared -

interface testInterface{}
class a implements testInterface{}
require 'b.php';
Keshari Nandan
  • 1,040
  • 9
  • 22