Amikor uniótípusokat használsz, tisztában kell lenned a kovariancia és a kontravariancia fogalmával. Ezeket a dokumentáció is elmagyarázza, de talán ezek a példák is segítenek.
Tegyük fel, hogy van egy Calculator osztályunk, amely az előző példához hasonló függvényt használ:
class Calculator
{
public function add(int|float $x, int|float $y): int|float
{
return $x + $y;
}
}
Ha kiterjeszted az osztályt, megváltoztathatod a paramétertípusokat és a visszatérési típusokat, de csak a következő szabályok szerint.
Először is, a paramétertípusok „szélesebbek” lehetnek, ami azt jelenti, hogy több típust fogadhatnak el, mint az ősosztály. Például ez megengedett:
class StringCalc extends Foo
{
public function add(float|int|string $x, float|int|string $y): int|float
{
if (!is_numeric($x) || !is_numeric($y)) {
throw new \InvalidArgumentException('$x and $y must be numeric');
}
return $x + $y;
}
}
A StringCalc-et behelyettesíthetnénk az eredeti Calculator helyére, és minden továbbra is működne. A hívó továbbra is be tudná küldeni azt a float vagy int értéket, amit eredetileg is, és a visszatérési típus is a várt int vagy float lenne.
Hasonlóképpen szűkítheted a visszatérési típust, azaz konkrétabbá teheted azáltal, hogy típusokat veszel ki az unióból. Ez a példa kihasználja ezt a szabályt:
class IntCalc extends Calculator
{
public function add(float|int $x, float|int $y) : int
{
return (int)($x + $y);
}
}
Mivel az IntCalc továbbra is elfogad int és float értéket, gond nélkül helyettesítheti az eredeti Calculator-t.
Ha többet szeretnél megtudni arról, mi megengedett és mi nem, olvasd el a Liskov-féle helyettesítési elv (LSP) leírását.
Arra, hogy mi nem megengedett, nézd meg az alábbi InvalidCalc osztályt:
class InvalidCalc extends Calculator
{
public function add(int $x, int $y) : int|float|string
{
// Declaration must be compatible with Calculator->add(x: float|int, y: float|int)
// Return type declaration must be compatible with Calculator->add(x: float|int, y: float|int) : float|int
}
}
Az InvalidCalc osztály nem fog lefordulni, és két problémája is van. Mivel szűkítette a paraméterként elfogadható típusokat, az InvalidCalc nem helyettesítheti az eredeti Calculator-t, mert már nem fogad el float értéket. Ráadásul most már string-et is visszaadhat, ami szintén nincs benne az eredeti osztály megengedett visszatérési típusai között.