هنگام استفاده از انواع اتحادی باید با مفاهیم کوواریانس و کنتراواریانس آشنا باشید. این مفاهیم در مستندات توضیح داده شدهاند، اما این مثالها میتوانند کمککننده باشند.
فرض کنید کلاس Calculator را داریم که از تابعی مانند مثال بالا استفاده میکند:
class Calculator
{
public function add(int|float $x, int|float $y): int|float
{
return $x + $y;
}
}
اگر بخواهید کلاس را ارثبری کنید، مجاز هستید انواع پارامترها و انواع بازگشتی را تغییر دهید، اما فقط بر اساس قواعد زیر.
اول، انواع پارامتر میتوانند «گستردهتر» باشند، یعنی میتوانند انواع بیشتری نسبت به کلاس پایه بپذیرند. برای نمونه، این مجاز است:
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;
}
}
میتوانستیم StringCalc را بهجای Calculator اصلی بگذاریم و همهچیز همچنان کار میکرد. فراخوانیکننده همچنان میتوانست همان float یا int را که از قبل میتوانست بفرستد، و نوع بازگشتی هم همان int یا float مورد انتظار میبود.
بههمینترتیب، میتوانید نوع بازگشتی را محدودتر کنید، یعنی با حذف انواع از اتحاد آن را مشخصتر کنید. این مثال از این قاعده بهره میگیرد:
class IntCalc extends Calculator
{
public function add(float|int $x, float|int $y) : int
{
return (int)($x + $y);
}
}
از آنجا که IntCalc همچنان int و float را میپذیرد، میتواند بدون هیچ مشکلی جای Calculator اصلی را بگیرد.
برای مطالعهی بیشتر دربارهی آنچه مجاز است و آنچه نیست، میتوانید به اصل جانشینی لیسکوف (LSP) مراجعه کنید.
برای نمونهای از آنچه مجاز نیست، به InvalidCalc زیر نگاهی بیندازید:
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
}
}
کلاس InvalidCalc کامپایل نمیشود و دو مشکل دارد. InvalidCalc با کاهش آنچه بهعنوان پارامتر مجاز است، نمیتواند جای Calculator اصلی را بگیرد، چون دیگر float را نمیپذیرد. علاوه بر این، حالا میتواند string برگرداند که آن هم در محدودهی انواع بازگشتی مجاز کلاس اصلی نیست.