2

I am faced with an error when using __autoload().

Here is an example of two simple classes in the same file:

class A
{
    public function check($a, $b)
    {
        $subClass = new B();

        return $subClass->check($a);
    }
}

class B extends A
{
    public function check($a)
    {
        return $a;
    }
}
$a = new A();
$a->check(77, 44);

Everything is OK; and it works as expected. But when I create a file for each class and use __autoload(), there is an error:

Strict standards: Declaration of B::check() should be compatible with that of A::check()

To reproduce:

file A.php

class A
{
    public function check($a, $b)
    {
        $subClass = new B();

        return $subClass->check($a);
    }
}

file B.php:

class B extends A
{
    public function check($a)
    {
        return $a;
    }
}

file test.php

function __autoload($className)
{
    require_once $className . '.php';
}
$a = new A();
$a->check(77, 44);

So, why does this error appear only when using __autoload?

Boann
  • 48,794
  • 16
  • 117
  • 146
sergio
  • 5,210
  • 7
  • 24
  • 46
  • This is not because of `__autoload`; the same problem happens if you simply `include` the other files. But it is odd. – Boann Nov 23 '14 at 10:33
  • ok, so why this error appeared? I can set into check() method in class B everything as I want(because in class A() it doesn't an abstract method), but why error – sergio Nov 23 '14 at 10:35
  • So shouldn't `B::check()` defined with 2 argumnets as `A::check()`? – u_mulder Nov 23 '14 at 10:42
  • No, because A::check() isn't abstract as you can see – sergio Nov 23 '14 at 10:43
  • Some related topic http://stackoverflow.com/questions/3115388/declaration-of-methods-should-be-compatible-with-parent-methods-in-php/9243127#9243127 Maybe it helps, still I think that despite of `abstractness` declaration of inherited method should have the same number of arguments. – u_mulder Nov 23 '14 at 10:47

2 Answers2

2

Actually it's the non-autoload code that is being weird. The strict standards error is supposed to happen.

The reason why the error doesn't appear in the single-file case is due to a quirk of how PHP loads the classes, and the timing of when the error reporting mode is set. There is some explanation here: https://bugs.php.net/bug.php?id=46851.

In short:

  • If you define the classes in a separate file or files (such as with __autoload or include), they are loaded after you have turned on E_STRICT reporting in your main file, so you see the error.

  • If you define the classes directly in your main file, then the classes get loaded before the script starts running, before you turn on E_STRICT error reporting, so you don't see the error.

  • Oddly, if you define the classes in your main file but reverse the order (class B, then class A) you do see the error. According to the page linked above, this is because PHP doesn't load them until a bit later.

  • If you turn on E_STRICT error reporting in php.ini, so it is already on before the script starts, you see the error, regardless of how the classes are loaded.


To understand the purpose of the error, it is telling you that it is wrong for a subclass to override a method with a different number of arguments, which it is.

See Liskov substitution principle on Wikipedia:

The Liskov substitution principle states that, in a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.).

Currently we have this code:

$a = new A();
$a->check(77, 44);

Now since B extends A, this indicates that B is a subtype of A, and according to the above principle it should be logically possible for objects of type A to be replaced with objects of type B. But look what happens:

$a = new B();
$a->check(77, 44);

We call the check method as usual, but it is not expecting two arguments, so the call doesn't make sense.

The improper override works in PHP, because PHP is generally not very strict, but turning on strict standards errors lets it warn about this.

Boann
  • 48,794
  • 16
  • 117
  • 146
  • I turn on errors in ini file, and dont have errors whe all in simple file. Also, I really don't understand, according to polymorpphism I can do it, there is no error, so why I faced with this – sergio Nov 23 '14 at 10:54
  • @sergio I do see the error. Did you restart the server/etc after changing php.ini? Anyway, the error is correct; it is not proper for a class to override a method to take different arguments. – Boann Nov 23 '14 at 10:56
  • no, because I set it early, when installed on server. And after restart a thousend times) – sergio Nov 23 '14 at 10:57
  • Also using autoload firstly load class A, after class B, so the order is right – sergio Nov 23 '14 at 11:01
  • @sergio The order is irrelevant when you use __autoload, because E_STRICT is already turned on by that time. – Boann Nov 23 '14 at 11:03
  • ok, so what's the reason of this? is there any docs or rules about this? – sergio Nov 23 '14 at 11:06
  • @sergio I've updated my answer. I hope it explains better now. – Boann Nov 23 '14 at 11:14
  • thank's, I knew about this, but it's realy strange behaviour of simple page, +1 more strange thing in php) – sergio Nov 23 '14 at 11:20
1

This message means that there are certain possible method calls which may fail at run-time. return $subClass->check($a); calls to class B method which has signature in parent method in class class A.

Different signature (2 parameters in A and 1 parameter in B) produces strict error, abstract or not.

It works if signatures are same:

class A
{
    public function check($a, $b)
    {
        $subClass = new B();

        return $subClass->check($a, NULL);
    }
}

class B extends A
{
    public function check($a, $b)
    {
        return $a;
    }
}

function __autoload($className)
{
    require_once $className . '.php';
}
$a = new A();
$a->check(77, 44);

Can I ask you what are you trying to achieve by instantiating new class in class which is extended by it?

Damaged Organic
  • 8,175
  • 6
  • 58
  • 84
  • this is not the answer why this error appears in autoload. Also according to inheritance and polymorphism in this case I can change the number of parameters. – sergio Nov 23 '14 at 10:51
  • As @Boann pointed out, this is not the matter of autoload, it also happens with `include()`. By the way, I get same error even if everything in one file. – Damaged Organic Nov 23 '14 at 10:55
  • One more thing, you say this is possible according to inheritance and polymorphism, right, but thats `E_STRICT`. – Damaged Organic Nov 23 '14 at 11:06
  • yes, but this not accroding rules about inheritance and polymorphism, I realy try to find info about this, something like exception from the rule, but nothing – sergio Nov 23 '14 at 11:09