آموزش interface در PHP : تعریف و استفاده

در این آموزش با مفهوم interface در PHP آشنا می‌شویم. رابط یا اینترفیس برای ما مشخص می‌کند که یک کلاس خاص باید چه متدهایی را داشته باشد. در حین آموزش کدهای یک مثال واقعی را با هم پیش می‌بریم تا درک بهتری از موضوع پیدا کنید.

در آموزش اصول برنامه نویسی شیء گرا مفهومی به نام چندریختی یا Polymorphism را معرفی کردم. اینطوری می‌توانستیم یک کلاس کلی را در اشکال مختلف اما با عملکردهای شبیه به هم داشته باشیم.

مثلاً مفهوم خودرو، یک انتزاعی است و به چیزهایی گفته می‌شود که چند چرخ، یک موتور و اجزای مشابهِ دیگری دارند. هر کدام از خودروها می‌توانند ویژگی‌های خاصی داشته باشند اما حتماً همگی روشن می‌شوند، راهنما می‌زنند، حرکت می‌کنند و … .

interface در PHP چیست؟

بیایید بحث را وارد دنیای برنامه‌نویسی کنیم. فرض کنید می‌خواهیم در یک سیستم فروشگاهی چندین درگاه پرداخت مختلف را پیاده‌سازی کنیم؛ برای مثال درگاه‌های بانک ملت و سامان.

اگر تفکر شیءگرایی (Object Oriented) داشته باشیم، در نگاه اول سعی می‌کنیم دو کلاس برای درگاه‌های موردنظرمان ایجاد کنیم. این روش کاملاً درست و بدون مشکل است.

اما آیا قبول دارید که همهٔ درگاه‌ها، رفتارهای (methodهای) مشابهی دارند؟ مثلاً همگی کاربر را به سایت درگاه ارجاع می‌دهند، پس از برگشت از درگاه وضعیت پرداخت را چک می‌کنند و اطلاعات تراکنش را در دیتابیس ذخیره می‌کنند؟

اگر هر کدام از کلاس‌های ما برای این متدها، نام‌های متفاوتی داشته باشند، ایجاد تغییرات در کدها پیچیده شده و گاهی روند توسعه برنامه‌ها را مختل می‌کند!

اینترفیس (interface) مشابه یک سند است که برای برنامه‌نویس‌ها مشخص می‌کند کلاس‌هایی با هدف یکسان باید حاوی چه متدهایی باشند؟ به این صورت مطمئن هستیم کلاس‌های مدنظرمان از ساختاری یکسان تبعیت می‌کنند.

تعریف اینترفیس با کد PHP

برای تعریف interface می‌بایست یک فایل php با نام اینترفیس موردنظرمان ایجاد کنیم. اینجا PaymentInterface.php را ساخته و قطعه کد زیر را در آن قرار می‌دهم:

interface PaymentInterface {
    // an Empty Interface
}

برای تعریف، ابتدا کلمهٔ interface را نوشته و سپس نامش را می‌نویسیم. دقیقاً مشابه تعریف کلاس در PHP که در دو جلسه قبل با آن آشنا شدیم، با این تفاوت که به جای class از interface استفاده می‌کنیم.

حالا می‌خواهیم مشخص کنیم کلاس‌هایی که از این اینترفیس پیروی می‌کنند باید چه متدهایی را حتماً پیاده‌سازی کنند. برای این کار، مشابه تعریف method عمل می‌کنیم اما فقط تا قسمت تعریف آرگومان‌های ورودی تابع PHP پیش می‌رویم:

<?php
interface PaymentInterface {

   public function pay($uid, $oid);
   public function verify($oid);
   public function receipt();

}

به این قسمت از یک متد (متد بدون بدنه) اصطلاحاً امضا یا شناسه متد نیز گفته می‌شود؛ چون هویتش (نام، ورودی و حتی نوع خروجی) را مشخص می‌کند.

در مثال بالا سه متد تعریف کرده‌ام:

  • متد pay که فرضاً id کاربر و سفارش را گرفته و پس از پردازش‌های لازم، کاربر را به درگاه منتقل می‌کند.
  • متد verify که برای تأیید وضعیت نهایی پرداخت (payment_id) و تطابق آن با مبلغ سفارش استفاده می‌شود. (oid شناسه سفارش است.)
  • انتظار داریم متد receipt نیز یک رشته متنی PHP به‌عنوان رسید پرداخت (مثلاً تاریخ و کد پیگیری) به ما نمایش دهد.

توجه کنید که نمی‌توانیم از interfaceها شیء ایجاد کنیم! یعنی در این مثال نوشتن new PayemtnInterface() اشتباه بوده و باعث ایجاد خطا می‌شود.

استفاده از interface

حالا برای استفاده از interface در php یک فایل دیگر برای تعریف کلاس درگاه موردنظرمان ایجاد می‌کنیم. برای اینکه مشخص کنیم یک کلاس قرار است از قرارداد اینترفیسِ خاصی پیروی کند، از کلمه implements استفاده می‌کنیم.

فایلی به نام MellatPayment.php ایجاد کرده و قطعه کد زیر را در آن قرار می‌دهم:

<?php

class MellatPayment implements PaymentInterface {
   // Class Body
}

می‌دانیم که می‌توانیم از یک کلاس خالی هم شیء جدید بسازیم. (هرچند کاربرد خاصی ندارد! 🙁 )

<?php
include 'MellatPayment.php';

$wrong_test = new MellatPayment();

اگر در همین فایل یا یک فایل کناری، سعی کنم از کلاس MellayPayment شئ جدید بسازم، با خطایی شبیه به خطای زیر مواجه می‌شوم:

Fatal error: Class SabzDanesh\MellatPayment contains 3 abstract methods and must therefore be declared abstract or implement the remaining methods
(SabzDanesh\PaymentInterface::pay, SabzDanesh\PaymentInterface::verify, SabzDanesh\PaymentInterface::receipt)
in /home/SabzDanesh/interface/MellatPayment.php on line 4

بنابراین بدون پیاده‌سازی متدهایی که در interface تعیین کرده‌ایم، نمی‌توانیم از کلاسمان استفاده کنیم. من یک بدنهٔ ساده برای توابع ایجاد می‌کنم تا بتوانیم آن را تست کنیم:

<?php
namespace SabzDanesh;

class MellatPayment implements PaymentInterface {

   public function pay($uid, $oid){
      echo "You're redirecting to Mellat gateway...";
   }

   public function verify($oid){
      echo "final Result shows here.";
   }

   public function receipt(){
      echo "123456 (2022/06/30 18:37:11)";
   }
}

اکنون می‌توانیم یک شئ از این کلاس ایجاد کرده و از آن استفاده کنیم:

<?php
namespace SabzDanesh;

$pay = new MellatPayment();
$pay->pay(8, 19);
خروجی استفاده از interface در درگاه
نتیجه استفاده از interface در کلاس درگاه با PHP

در پیاده‌سازی interface در PHP هیچ محدودیتی در تعداد اینترفیس‌هایی که یک کلاس از آن‌ها پیروی می‌کند نداریم. در مقابل، اگر از چند جلسهٔ قبلی (ارث‌بری کلاس‌ها در PHP) یادتان باشد، در هر کلاس صرفاً می‌توانیم از یک کلاس دیگر ارث‌بری کنیم.

مثال چندگانه interface در php

فرض کنید یک اینترفیس به نام Printable داریم که به ما اجازه می‌دهد کلاسمان را قابل پرینت کنیم؛ مثلاً اطلاعات را در یک ساختار منظم برای چاپ روی کاغذ در مرورگر کاربر نمایش دهیم.

این اینترفیس فقط یک متد به نام print() دارد. ما می‌توانیم کلاس درگاهی که نوشته‌ایم مجبور کنیم علاوه بر قرارداد درگاه‌ها (PaymentInterface)، از Printable هم پیروی کند.

در این حالت احتمالاً کدی شبیه به قطعه کد زیر خواهیم داشت:

<?php
namespace SabzDanesh;

class MellatPayment implements PaymentInterface, Printable {

  public function pay($uid, $oid){
      // TODO: Implement pay() method.
   }

   public function verify($oid){
      // TODO: Implement verify() method.
   }

   public function receipt(){
      // TODO: Implement receipt() method.
   }

   public function print(){
      // TODO: Implement print() method.
   }
}

مزایای interface در php

به عنوان یکی از کاربردهای interface در PHP می‌توان به ایجاد هماهنگی در پروژه‌های بزرگ اشاره کرد. فرض کنید همین ساختار فروشگاه اینترنتی را بخواهیم در یک تیم چند نفره پیاده‌سازی کنیم. با تعریف اینترفیس یا رابط برای مفاهیم اصلی در سیستم، مطمئن خواهیم بود همهٔ پیاده‌سازی‌ها و بخش‌های برنامه از یک قانون ثابت پیروی خواهند کرد.

همچنین اگر در آینده بخواهیم از درگاه‌های ملت و سامان به درگاه دیگری مثل ایران کیش مهاجرت کنیم، فقط کافی است کلاس مورد نظر را برنامه‌نویسی کرده و از آن استفاده کنیم. بنابراین همیشه اطمینان داریم متدهای ضروری در کلاس‌های جدید نیز پیاده‌سازی می‌شوند.

امیدوارم با این آموزش با نحوه کار با interfaceها و چرایی استفاده از آن‌ها در برنامه‌نویسی PHP آشنا شده باشید. قطعاً لازم است یک مینی پروژه برای تثبیت یادگیری خودتان با این تعاریف پیاده‌سازی کنید.

یک مثال کلیشه‌ای برای بحث ارث‌بری و interfaceها ارتباط بین مفهوم حیوان با سگ و گربه و … است. اگر دوست دارید کدهای چنین مثالی را ببینید، این صفحه از w3schools خوب است.

اگر سؤال، چالش یا نکته‌ای در این مورد دارید، بخش دیدگاه‌ها برای شماست، وگرنه همین الآن به جلسه بعدی مراجعه کنید. 🙂

این آموزش بخشی از یک آموزش جامع و قدم به قدم در سبز دانش است: دوره رایگان آموزش PHP