PHP严格标准:声明应兼容

前端之家收集整理的这篇文章主要介绍了PHP严格标准:声明应兼容前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有以下层次结构的类:
class O_Base {...}

class O extends O_Base {...}

abstract class A_Abstract {
    public function save(O_Base $obj) {...}
}

class A extends A_Abstract {
    public function save(O $obj) {
        echo 'save!';
    }
}

$o = new O;
$a = new A;

$a->save($o);

当我运行这个代码,我得到消息:

Strict Standards: Declaration of A::save() should be compatible with
A_Abstract::save(O_Base $obj) in .PHP on line 21

我知道E_STRICT错误级别,但我找不到(并理解)该行为的原因.有谁能够帮助我?

您的代码明确违反了 the Liskov Substitution principle.抽象类需要将O_Base的一个实例传递给save方法,因此A_Abstract的所有子节点都应该被定义为可以接受O_Base的所有实例.您的子类实现了进一步限制API的保存版本. see another example here

在你的代码中,A违反了Abstract_A强制执行/描述的合同.就像在现实生活中一样,如果您签署合同,您必须在某些条款上达成一致,并且都将与您将要使用的术语达成一致.这就是为什么大多数合同是以各方命名的方式开始的,然后再说“X以后就被称为员工”.
这些术语,像你的抽象类型提示是不可忽视的,所以,进一步下线,你不能说:“哦,好吧,你所说的费用,我称为标准工资”
好的,我会停止使用这些半数的类比,只需使用一个简单的例子来说明为什么你正在做的是正确的,不允许的.

考虑这个:

abstract class Foo
{
    abstract public function save(Guaranteed $obj);
    //or worse still:
    final public function doStuff(Guaranteed $obj)
    {
        $obj->setSomething('to string');
        return $this->save($obj);//<====!!!!
    }
}

class FBar extends Foo
{
    public function save(Guaranteed $obj)
    {
        return $obj->setFine(true);
    }
}

class FBar2 extends Foo
{
    public function save(ChildOfGuaranteed $obj)
    {//FAIL: This method is required by Foo::doStuff to accept ALL instances of Guaranteed
    }
}

看这里,在这种情况下,完全有效的抽象类正在调用一个保证实例的save方法.如果您被允许在此类的子级中强制执行更严格的类型提示,则可以轻松地打破此doStuff方法.为了帮助您保护自己免受这些自我伤害的伤害,儿童课程不应该被允许对父母继承的方法执行更严格的类型.
还要考虑一下我们循环一些实例并检查它们是否具有此保存方法的场景,基于这些实例是Foo的一个实例:

$arg = new OtherChildOfGuaranteed;
$array = array(
    'fb'  => new FBar,'fb2' => new FBar2
);
foreach($array as $k => $class)
{
    if ($class instanceof Foo) $class->save($arg);
}

现在,如果您只是在方法签名中提示“保证”,则此操作将正常工作.但是在第二种情况下,我们已经提出了类型提示有点太严格,这个代码将导致致命的错误.在一个更复杂的项目中调试这个有趣的乐趣…

PHP在很多情况下是非常原谅的,如果不是宽恕,但不在这里.而不是让你搔头,直到你的听力下降,PHP非常明智地给你一个头脑,说你的方法的执行违反了合同,所以你必须解决这个问题.

现在,快速解决方法(也是一个常用的)将是这样的:

class FBar2 extends Foo
{
    /**
     * FBar2 save implementation requires instance of ChildOfGuaranteed
     *  Signature enforced by Foo
     * @return Fbar2
     * @throw InvalidArgumentException
     **/
    public function save(Guaranteed $obj)
    {
        if (!$obj instanceof ChildOfGuaranteed)
            throw new InvalidArgumentException(__METHOD__.' Expects instance of ChildOfGuaranteed,you passed '.get_class($obj));
        //do save here...
    }
}

所以,你只是按照原样离开抽象类型提示,但是使用docblock来记录你的代码

猜你在找的PHP相关文章