Skip to content

6. رابط‌ها

یک رابط ساختاری است که پروتو‌تایپ متدها را تعریف می‌کند. کلاسی که رابط را پیاده‌سازی می‌کند باید کد تمام متدهای موجود در آن رابط را تعریف کند.

6.1. درخت اسکریپت

Image

6.2. یک رابط اول

ما یک رابط [IExemple] را در یک اسکریپت [IExemple.php] تعریف می‌کنیم. در همان اسکریپت، دو کلاس را که رابط [IExemple] را پیاده‌سازی می‌کنند، تعریف می‌کنیم:


<?php

// پابندی سخت‌گیرانه به انواع پارامترهای تابع
declare(strict_types=1);

// فضای نام
namespace Exemples;

// یک رابط
interface IExemple {
    // متدهای این رابط
    public function ajouter(int $i, int $j): int;
    public function soustraire(int $i, int $j): int;
}

//پیاده‌سازی ۱ از رابط IExemple
class Classe1 implements IExemple {
    public function ajouter(int $a, int $b): int {
        return $a + $b + 10;
    }

    public function soustraire(int $a, int $b): int {
        return $a - $b + 20;
    }

}

//پیاده‌سازی دوم رابط IExemple
class Classe2 implements IExemple {
    public function ajouter(int $a, int $b) : int{
        return $a + $b + 100;
    }

    public function soustraire(int $a, int $b) : int {
        return $a - $b + 200;
    }

}

توضیحات

  • خطوط ۱۰–۱۴: رابط IExemple دو متد را تعریف می‌کند: تابع ajouter (خط ۱۲) و تابع soustraire (خط ۱۳). این رابط کد این متدها را تعریف نمی‌کند. این کار توسط کلاس‌هایی که این رابط را پیاده‌سازی می‌کنند انجام می‌شود؛
  • خط 17: کلاس Classe1 رابط IExemple را پیاده‌سازی می‌کند. بنابراین کد مربوط به متدهای ajouter (خط ۱۸) و soustraire (خط ۲۲) را تعریف می‌کند؛
  • خطوط ۲۹–۳۸: همین امر در مورد کلاس Classe2 نیز صدق می‌کند؛

ما از رابط [IExemple] در اسکریپت زیر [interfaces-01.php] استفاده می‌کنیم:


<?php

require_once "IExemple.php";
use \Exemples\Classe1;
use \Exemples\Classe2;
use \Exemples\IExemple;

// تابع
function calculer(int $a, int $b, IExemple $interface) : void {
  print $interface->ajouter($a, $b)."\n";
  print $interface->soustraire($a, $b)."\n";
}

// ------------------- اصلی
// ایجاد ۲ شیء از نوع Class1 و Class2
$c1 = new Classe1();
$c2 = new Classe2();
// فراخوانی تابع 'محاسبه'
calculer(4, 3, $c1);
calculer(14, 13, $c2);

نظرات

  • خطوط ۳–۶: درج و تعریف کلاس‌ها و رابط‌هایی که توسط اسکریپت استفاده می‌شوند؛
  • خط ۳: به جای دستور `include`، در اینجا از دستور `require_once` استفاده شده است. دستور `include` یک فایل را در اسکریپت جاری وارد می‌کند حتی اگر قبلاً وارد شده باشد، در حالی که دستور `require_once` آن را فقط یک بار وارد می‌کند. بنابراین، در مورد وارد کردن کد، دستور `require_once` را ترجیح می‌دهیم؛
  • خطوط ۹–۱۲: ما یک تابع تعریف می‌کنیم؛
  • خط ۹: در اینجا نوع سه پارامتر را اعلام کرده‌ایم. اگر در زمان اجرا، پارامتر واقعی از نوع مورد انتظار نباشد، یک خطا پرتاب می‌شود. پارامتر سوم از نوع [IExemple] است. این بدان معناست که پارامتر واقعی باید یک نمونه از کلاسی باشد که رابط [IExemple] را پیاده‌سازی می‌کند؛ بنابراین در مثال ما، یک نمونه از کلاس‌های [Classe1] یا [Classe2]؛
  • خطوط ۱۰–۱۱: ما از متدهای [ajouter, soustraire] از رابط [IExemple] استفاده می‌کنیم؛
  • خط ۱۹: سومین پارامتر واقعی از نوع [Classe1] است که با نوع [IExemple] سومین پارامتر اسمی تابع سازگار است؛
  • خط ۲۰: همین امر در مورد کلاس [Classe2] نیز صدق می‌کند؛

نتایج

1
2
3
4
17
21
127
201

6.3. ارث‌بری از یک رابط

همان‌طور که یک کلاس فرزند می‌تواند یک کلاس والد را گسترش دهد، یک رابط فرزند نیز می‌تواند یک رابط والد را گسترش دهد.

رابط [IExemple2] را که در فایل [IExemple2.php] تعریف شده است، در نظر بگیرید:


<?php

// رعایت دقیق انواع پارامترهای تابع
declare(strict_types=1);
// فضای نام
namespace Exemples;

// شامل تعریف رابط IExemple
require_once __DIR__."/IExemple.php";

// یک رابط که از IExemple ارث می‌برد
interface IExemple2 extends IExemple {
    // روش رابط
    public function multiplier(int $i, int $j): int;
}

//پیاده‌سازی رابط IExemple2
class Classe3 extends Classe2 implements IExemple2 {
   
    public function multiplier(int $a, int $b): int {
        return $a * $b;
    }

}

توضیحات

  • خط ۶: رابط [IExemple2] در همان فضای نامی (namespace) رابط [Iexemple] قرار خواهد گرفت؛
  • خط ۹: فایل تعریف برای رابط [Iexemple] گنجانده شده است؛
  • خطوط ۱۲–۱۵: رابط [IExemple2] را تعریف کنید، که رابط [Iexemple] را گسترش می‌دهد و یک متد جدید به آن اضافه می‌کند (خط ۱۴)؛
  • خطوط ۱۸–۲۴: کلاس [Classe3] از کلاس [Classe2] ارث می‌برد. از آنجا که مورد دوم رابط [IExemple] را پیاده‌سازی می‌کند، کلاس [Classe3] نیز این کار را انجام خواهد داد. در واقع، [Classe3] تمام متدهای عمومی و محافظت‌شده کلاس [Classe2] را، از جمله متدهای «add» و «subtract»، ارث می‌برد. علاوه بر این، ذکر شده است که [Classe3] رابط [IExemple2] را پیاده‌سازی می‌کند. بنابراین، باید متد `multiplier` را نیز پیاده‌سازی کند، کاری که [Classe2] انجام نمی‌دهد. این کاری است که خطوط ۲۰ تا ۲۲ انجام می‌دهند؛

رابط [IExemple2] توسط اسکریپت زیر [interfaces-02] استفاده می‌شود:


<?php

// پابندی سخت‌گیرانه به انواع پارامترهای تابع
declare(strict_types=1);

// شامل و واجد شرایط‌سازی کلاس‌ها و رابط‌های مورد نیاز اسکریپت
require_once __DIR__."/Iexemple2.php";
use \Exemples\IExemple2;
use \Exemples\Classe3;

// تابع
function calculer(int $a, int $b, IExemple2 $interface) {
    print $interface->ajouter($a, $b) . "\n";
    print $interface->soustraire($a, $b) . "\n";
    print $interface->multiplier($a, $b) . "\n";
}

// ------------------- main
// ایجاد ۱ شیء از نوع Class3 که IExemple2 را پیاده‌سازی می‌کند
$c3 = new Classe3();
// فراخوانی تابع 'calculate'
calculer(4, 3, $c3);

توضیحات

  • خط ۱۲: پارامتر سوم تابع [calculer] از نوع [IExemple2] است؛
  • خطوط ۱۳–۱۵: سه متد رابط [IExemple2] استفاده می‌شوند؛
  • خط ۲۲: تابع [calculer] با یک شیء از نوع [IExemple2] (خط ۲۰) به‌عنوان سومین پارامتر فراخوانی می‌شود؛

نتایج

1
2
3
107
201
12

6.4. ارسال یک رابط به‌عنوان پارامتر تابع

در بخش قبلی دیدیم که وقتی نوع مورد انتظار برای یک پارامتر تابع یک کلاس است، پارامتر واقعی می‌تواند یک شیء از نوع مورد انتظار یا یک نوع مشتق باشد. همین موضوع در مورد اینترفیس‌ها نیز صدق می‌کند، همان‌طور که در اسکریپت زیر [interfaces-03.php] نشان داده شده است:


<?php

// رعایت دقیق انواع پارامترهای تابع
declare(strict_types=1);

// شامل کردن و مشخص کردن کلاس‌ها و رابط‌های مورد نیاز اسکریپت
require_once __DIR__."/IExemple.php";
use \Exemples\IExemple;
require_once __DIR__."/IExemple2.php";
use \Exemples\Classe3;

// تابع
function calculer(int $a, int $b, IExemple $interface) {
  print $interface->ajouter($a, $b) . "\n";
  print $interface->soustraire($a, $b) . "\n";
}

// ------------------- main
// ایجاد ۱ شیء از نوع Class3 که IExemple2 را پیاده‌سازی می‌کند و در نتیجه IExemple
$c3 = new Classe3();
// فراخوانی تابع 'محاسبه'
calculer(4, 3, $c3);

توضیحات

  • خط ۱۳: تابع [calculer] انتظار یک نوع [IExemple] را به عنوان سومین پارامتر خود دارد. این بدان معناست که پارامتر واقعی می‌تواند از نوع [IExemple] یا یک نوع مشتق باشد؛
  • خط ۲۰: یک شیء از نوع $c3 از کلاس [Classe3] نمونه سازی می‌شود، که رابط [IExemple2] را پیاده‌سازی می‌کند، که به نوبه خود رابط [IExemple] را گسترش می‌دهد. بنابراین، در نهایت، $c3 رابط [IExemple] را پیاده‌سازی می‌کند؛
  • خط ۲۲: تابع [calculer] با یک شی $c3 از نوع [Classe3] به عنوان سومین پارامتر فراخوانی می‌شود. از طریق ارث‌بری کلاس و پیاده‌سازی‌ها، دیده‌ایم که شیء $c3 نوع [IExemple] را پیاده‌سازی می‌کند. بنابراین می‌توان از آن به‌عنوان پارامتر سوم استفاده کرد؛

نتایج

107
201