To understand why they are treated differently, you have to understand Liskov's Substitution Principle, which states
If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T." - BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 (May, 1988).
In a nutshell this means any class using your Lion
or Cat
should be able to reliably call doSomething
on it, regardless of the class being one or the other. If you change the method signature, this is no longer guaranteed (you may widen it, but not narrow it though).
Very simple Example
public function doSomethingWithFeline(Cat $feline)
{
$feline->doSomething(42);
}
Since Lion extends Cat
, you established an is-a relationship, meaning doSomethingWithFeline
will accept a Lion
for a Cat
. Now imagine you add a required argument to doSomething
in Lion
. The code above would break because it is not passing that new param. Hence, the need for compatible signatures.
LSP does not apply to constructors though, because subtypes might have different dependencies. For instance if you have a FileLogger and a DBLogger, the ctors (constructors) of the first would require a filename, while the latter would require a db adapter. As such, ctors are about concrete implementations and not part of the contract between classes.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…