它似乎对我来说(尽管它提出了一个严格的警告)与以下测试用例:
class PassMeIn
{
}
class PassMeInSubClass extends PassMeIn
{
}
class ClassProcessor
{
public function processClass (PassMeIn $class)
{
var_dump (get_class ($class));
}
}
class ClassProcessorSubClass extends ClassProcessor
{
public function processClass (PassMeInSubClass $class)
{
parent::processClass ($class);
}
}
$a = new PassMeIn;
$b = new PassMeInSubClass;
$c = new ClassProcessor;
$d = new ClassProcessorSubClass;
$c -> processClass ($a);
$c -> processClass ($b);
$d -> processClass ($b);
如果严格的警告是你真的不想要的,你可以这样解决。
class ClassProcessor
{
public function processClass (PassMeIn $class)
{
var_dump (get_class ($class));
}
}
class ClassProcessorSubClass extends ClassProcessor
{
public function processClass (PassMeIn $class)
{
if ($class instanceof PassMeInSubClass)
{
parent::processClass ($class);
}
else
{
throw new InvalidArgumentException;
}
}
}
$a = new PassMeIn;
$b = new PassMeInSubClass;
$c = new ClassProcessor;
$d = new ClassProcessorSubClass;
$c -> processClass ($a);
$c -> processClass ($b);
$d -> processClass ($b);
$d -> processClass ($a);
有一件事你应该记住,这绝对不是OOP术语中的最佳实践。如果超类可以接受特定类的对象作为方法参数,那么所有的子类也应该能够接受该类的对象。防止子类处理超类可以接受的类意味着您不能使用该子类代替超类,并且100%相信它将在所有情况下都可以正常工作。相关的实践被称为Liskov Substitution Principle,它指出,除了别的以外,方法参数的类型只能在子类中变弱,返回值的类型只能变得更强(输入只能得到更一般的,输出只能得到更具体)。
这是一个非常令人沮丧的问题,我自己刷了很多次,所以如果在特定情况下忽略它是最好的事情,那么我建议你忽略它。但是不要习惯它,或者你的代码将开始开发各种微妙的相互依赖,这将是一个噩梦调试(单元测试不会捕捉到它们,因为单个单元将按照预期的行为,它们之间的相互作用问题在哪里)。如果你不理会它,那么评论代码让别人知道它,这是一个刻意的设计选择。