gpt4 book ai didi

PHP严格标准: Declaration of should be compatible

转载 作者:行者123 更新时间:2023-12-03 00:04:47 27 4
gpt4 key购买 nike

我有以下类层次结构:

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所有实例。您的子类实现了 save 的版本这进一步限制了 API。 see another example here

在您的代码中,A违反契约(Contract) Abstract_A强制执行/描述。就像在现实生活中一样,如果您签署契约(Contract),则必须就某些条款达成一致,并且所有人都就您将要使用的术语达成一致。这就是为什么大多数契约(Contract)都以指定当事人的名字开始,然后说一些类似于“从此以后 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实例为 Guaranteed 的方法。如果您被允许在此类的子级中强制执行更严格的类型提示,您可以轻松打破此 doStuff方法。为了帮助您保护自己免受此类自伤,不应允许子类对从父类继承的方法强制执行更严格的类型。
还要考虑这样的场景:我们循环某些实例并检查它们是否具有此 save方法,基于这些实例是 instanceof Foo :

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

现在,如果您只是提示 Guaranteed ,这将正常工作。在方法签名中。但在第二种情况下,我们使类型提示有点过于严格,并且此代码将导致 fatal error 。在更复杂的项目中享受调试的乐趣......

PHP 非常宽容,即使在大多数情况下不是太宽容,但这里不是。 PHP 不会让您摸不着头脑直到听不清,而是非常明智地向您发出警告,说您的方法的实现违反了契约(Contract),因此您必须解决这个问题。

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

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...
}
}

因此,您只需按原样保留抽象类型提示,但使用文档 block 来记录您的代码

关于PHP严格标准: Declaration of should be compatible,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21092605/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com