致命错误:声明.必须兼容.PHP(所需参数:规范的扩展类)


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

然后我做了两个类扩展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,系统就会工作得很好。然而,我担心我可能没有正确理解接口/抽象类!

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

您的参数类型必须在接口(或抽象类)和您实现相同的地方相同。现在的接口是LangPrefSet_ReconcilableLangPrefSet_ResourceLangPrefSet_For_User .

你可以像下面那样使用第二个接口,或者使用相同的类。

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

问题可能是在抽象类声明中,我指定任何 LangPrefSet必须为reconcile()对象方法所接受:

abstract public function reconcile(LangPrefSet $other);

-然而在实际的方法声明中,我在一种情况下指定只有一个LangPrefSet_Resource是可接受的,在另一种情况下,只有一个LangPrefSet_For_User是可接受的。因此,对象方法声明与抽象方法声明不兼容。这些接口/抽象方法声明技术的正确应用似乎不是为了扩大实现接口的类中允许的参数类型约束的范围,因为我们可以简单地通过声明那些特定类/方法的输入限制来实现这一点;相反,接口/抽象方法声明的目的是扩大可以实际传递给指定这些抽象参数类型的方法的参数范围。