Fatal error: Declaration of .. must be compatible with .. PHP (parameter required: extended class of specification)

Fatal error: Declaration of .. must be compatible with .. PHP (parameter required: extended class of specification)

我正在开发我的语言限制协调系统的下一个版本。我从这个开始(abstract 函数声明似乎是问题所在):

namespace AAABIT;
abstract class LangPrefSet{
    private $LangPrefs;
    public function __construct(){$this->LangPrefs=array();}
    public function add(LangPref $langpref){$this->LangPrefs[]=$langpref;}
    public function langPrefs(){return $this->LangPrefs;}
    abstract public function reconcile(LangPrefSet $other);//←Seems to be throwing an error… We don't strictly need this line, but this is a little concerning…
    protected static function reconcile_LangPrefSets(LangPrefSet_ForUser $UserLangPrefSet,LangPrefSet_Resource $RsrcLangPrefSet,$maxOptions){//…
    }
}
//Following classes are necessary because language similarity is a one-way mapping. Just because resources in Lang A (e.g. Russian) are likely to be readily understandable for speakers/readers of Lang B (e.g. Ukrainian), does not mean that the resources in Lang B (e.g. Ukrainian) are equally intelligible for speakers/readers of Lang A (e.g. Russian)!
class LangPrefSet_For_User extends LangPrefSet{public function reconcile(LangPrefSet_Resource $RsrcLangPrefSet){return self::reconcile_LangPrefSets(self,$RsrcLangPrefSet);}}
class LangPrefSet_Resource extends LangPrefSet{public function reconcile(LangPrefSet_For_User $UserLangPrefSet){return self::reconcile_LangPrefSets($UserLangPrefSet,self);}}

我认为这可行,因为 LangPrefSet_Resource 符合 LangPrefSet;但是 PHP 发现这令人反感,抛出上述错误。我想我可能有更好的界面......所以我这样做了:

interface LangPrefSet_Reconcilable{
    public function reconcile(LangPrefSet_Reconcilable $other);
}

然后我做了两个 classes 扩展 LangPrefSet,implements LangPrefSet_Reconcilable,并注释掉了抽象函数声明(在第一次尝试使它需要一个 LangPrefSet_Reconcilable 接口类型的参数之后,也没有用)——结果是:

Fatal error: Declaration of AAABIT\LangPrefSet_For_User::reconcile() must be compatible with AAABIT\LangPrefSet_Reconcilable::reconcile(AAABIT\LangPrefSet_Reconcilable $other)

— 这对我来说不是阻碍问题,因为我可以去掉 abstract functioninterface,系统就可以正常工作。但是我担心我可能没有正确理解接口/抽象 classes!

指定覆盖 abstract function a(ObjB $b) 或类似接口规范的 class 方法有什么问题,将 ObjC $c 作为参数,其中 ObjC 扩展了 ObjB?

您的参数类型必须与接口(或抽象 class)中的相同,并且您在其中实现相同。现在界面是 LangPrefSet_Reconcilable 并且实现说 LangPrefSet_ResourceLangPrefSet_For_User.

您可以使用如下所示的第二个界面,或使用相同的 class。

interface LangPrefSetReconcilableDataInteface {
    ...
}

interface LangPrefSet_Reconcilable{
    public function reconcile(LangPrefSetReconcilableDataInteface $other);
}

class LangPrefSet_Resource implements LangPrefSetReconcilableDataInteface {
...
}

class LangPrefSet_For_User implements LangPrefSetReconcilableDataInteface {
...
}

class LangPrefSet_For_User extends LangPrefSet
{
    public function reconcile(LangPrefSetReconcilableDataInteface $RsrcLangPrefSet)
    {
        return self::reconcile_LangPrefSets(self,$RsrcLangPrefSet);
    }
}

class LangPrefSet_Resource extends LangPrefSet
{
    public function reconcile(LangPrefSetReconcilableDataInteface $UserLangPrefSet)
    {
        return self::reconcile_LangPrefSets($UserLangPrefSet,self);
    }
}

问题可能是在抽象 class 声明中,我指定 any LangPrefSet 必须被 reconcile() 对象方法:

abstract public function reconcile(LangPrefSet $other);

— 而在实际的方法声明中,我在一种情况下指定 only a LangPrefSet_Resource 是可以接受的,而在另一种情况下,只有一个LangPrefSet_For_User是可以接受的。

因此对象方法声明与抽象方法声明不兼容。似乎这些 interface/abstract 方法声明技术的正确应用不是扩大实现接口的 classes 中允许的参数类型约束的范围,因为我们可以通过简单地声明输入限制来实现这一点因为它们应该适用于那些特定的 classes/methods;而是,interface/abstract 方法声明旨在扩大可能实际传递给指定这些抽象参数类型的方法的参数范围。