使用__autoload时严格标准错误

时间:2014-11-23 10:28:25

标签: php autoload

使用__autoload()时,我遇到了错误。

以下是同一文件中两个简单类的示例:

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);

一切都好;它按预期工作。但是当我为每个类创建一个文件并使用__autoload()时,会出现错误:

  

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

要重现:

文件A.php

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

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

文件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);

那么,为什么只有在使用__autoload

时才会出现此错误

2 个答案:

答案 0 :(得分:2)

实际上它是 -autoload代码很奇怪。严格的标准错误应该发生

错误没有出现在单文件案例中的原因是由于PHP加载类的方式的怪癖,以及设置错误报告模式的时间。这里有一些解释:https://bugs.php.net/bug.php?id=46851

简而言之:

  • 如果您在单独的文件或文件中定义类(例如使用__autoloadinclude),则在主文件中打开E_STRICT报告后会加载它们,因此你看错了。

  • 如果直接在主文件中定义类,则在脚本开始运行之前加载类,然后再打开E_STRICT错误报告,这样您就不会看到错误。

  • 奇怪的是,如果您在主文件中定义类但是反转顺序(B类,然后是A类),您会看到错误。根据上面链接的页面,这是因为PHP稍后不会加载它们。

  • 如果在php.ini中打开E_STRICT错误报告,那么在脚本启动之前它已经打开,无论类如何加载,都会看到错误。


为了理解错误的目的,它告诉你,子类覆盖具有不同数量的参数的方法是错误的。

请参阅维基百科上的Liskov substitution principle

  

Liskov替换原则指出,在计算机程序中,如果S是T的子类型,则类型T的对象可以用类型S的对象替换(即,类型S的对象可以替换 T类型的对象,而不改变该程序的任何所需属性(正确性,执行任务等)。

目前我们有这段代码:

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

现在由于B扩展了A,这表明B是A的子类型,并且根据上述原则,类型A的对象在逻辑上应该被B类对象替换。但是看看会发生什么: / p>

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

我们像往常一样调用check方法,但它没有期待两个参数,所以调用没有意义。

不正确的覆盖在PHP中起作用,因为PHP通常不是很严格,但是打开严格的标准错误会让它发出警告。

答案 1 :(得分:1)

此消息表示某些可能的方法调用可能在运行时失败。 return $subClass->check($a);调用class B方法,该方法在类class A中的父方法中具有签名。

不同的签名(A中的2个参数和B中的1个参数)产生严格的错误,抽象与否。

如果签名相同,则有效:

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);

我可以通过在类中扩展实例化新类来问你想要实现什么目标吗?