|
<?php |
|
|
|
// PHP RFC: Parameter Type Widening (Contravariant argument type) |
|
// https://wiki.php.net/rfc/parameter-no-type-variance |
|
// It's not real contravariance. Type widening doesn't allow to use arbitrary supertype, only mixed (by ommiting type). |
|
// Otherwise, parameter types in PHP are invariant. |
|
// This correspond with behaviour of return types, which are kind of covariant |
|
// https://3v4l.org/jU9IC |
|
|
|
|
|
class A {} |
|
class B extends A {} |
|
class C extends B {} |
|
class X {} |
|
|
|
class Foo { |
|
public function bar(B $b) {} |
|
} |
|
|
|
class Woo extends Foo { |
|
public function bar(/*mixed*/ $b) {} |
|
} |
|
|
|
$foo = new Foo(); |
|
$woo = new Woo(); |
|
|
|
// $foo->bar(new A);// A is too generic, Foo::bar() expects more specific type B |
|
// TypeError: Argument 1 passed to Foo::bar() must be an instance of B, instance of A given |
|
$foo->bar(new B); // this is ok, B is expected type |
|
$foo->bar(new C); // this is ok, C is subtype of B |
|
// $foo->bar(new X);// X isn't subtype of B |
|
// TypeError: Argument 1 passed to Foo::bar() must be an instance of B, instance of X given |
|
|
|
$woo->bar(new A); // this is ok, A is subtype of mixed |
|
$woo->bar(new B); // this is ok, B is subtype of mixed |
|
$woo->bar(new C); // this is ok, C is subtype of mixed |
|
$woo->bar(new X); // this is ok, X is subtype of mixed |
|
$woo->bar([]); // this is ok, array is subtype of mixed |
|
$woo->bar(123); // this is ok, int is subtype of mixed |
|
|
|
function baz(Foo $f) { |
|
// Foo:bar() accept only B and its subtypes (ie. B and C) |
|
// and these types are safe also for Woo:bar() if Woo is up-casted to Foo |
|
$f->bar(new C); |
|
} |
|
|
|
baz($foo); |
|
baz($woo); // inside of baz function, Woo is up-casted to Foo |