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错误级别,但我找不到(并理解)该行为的原因.有谁能够帮助我?
在你的代码中,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... } }