Interface در PHP یکی از مهمترین مفاهیم برنامهنویسی شیگرا (OOP) است که برای تعریف یک قرارداد مشخص بین Classها استفاده میشود.
اگر بخواهیم خیلی ساده توضیح دهیم، Interface به ما میگوید:
> یک Class که این Interface را پیادهسازی میکند، باید رفتارهای مشخصی را ارائه دهد.
برای مثال فرض کنید در یک فروشگاه اینترنتی چند روش پرداخت داریم:
- پرداخت آنلاین
- پرداخت از کیف پول
- پرداخت با یک Gateway خارجی
- پرداخت از طریق یک درگاه ایرانی
نحوه اجرای هرکدام متفاوت است، اما سیستم ما انتظار دارد همه آنها یک عملیات مشخص مثل pay() داشته باشند.
در اینجا میتوانیم یک Interface تعریف کنیم:
interface PaymentGateway
{
public function pay(float $amount): bool;
}
سپس هر درگاه پرداخت این قرارداد را پیادهسازی کند.
این کار باعث میشود بخشهای مختلف برنامه بدون وابستگی شدید به یک پیادهسازی خاص، با یک قرارداد مشخص کار کنند.
در این مقاله یاد میگیریم:
- Interface در PHP چیست؟
- Interface چه کاربردی دارد؟
- چگونه یک Interface ایجاد کنیم؟
implementsچیست؟- چگونه یک Interface را در Class پیادهسازی کنیم؟
- آیا یک Class میتواند چند Interface داشته باشد؟
- تفاوت Interface و Abstract Class چیست؟
- Interface چه تفاوتی با Inheritance دارد؟
- Interface چه نقشی در Polymorphism دارد؟
- چگونه از Interface در پروژههای واقعی PHP استفاده کنیم؟
- Interface در Laravel چه کاربردی دارد؟
- چه زمانی استفاده از Interface مناسب است؟
# Interface در PHP چیست؟
Interface در PHP یک قرارداد برای Classها تعریف میکند.
برای ایجاد Interface از کلمه کلیدی:
interface
استفاده میکنیم.
مثلاً:
interface PaymentGateway
{
public function pay(float $amount): bool;
}
در این مثال Interface اعلام میکند هر Classی که PaymentGateway را پیادهسازی میکند، باید Method زیر را داشته باشد:
pay()
با امضای مشخصشده.
خود Interface معمولاً منطق اصلی اجرای عملیات را پیادهسازی نمیکند؛ بلکه مشخص میکند Class پیادهساز چه قراردادی را باید رعایت کند.
# Interface در PHP چه کاربردی دارد؟
یکی از مهمترین کاربردهای Interface، کاهش وابستگی بین بخشهای مختلف نرمافزار است.
فرض کنید یک فروشگاه اینترنتی داریم و برای پرداخت از یک درگاه خاص استفاده میکنیم.
اگر کد ما مستقیماً به Class مربوط به آن درگاه وابسته باشد:
$gateway = new ZarinpalGateway();
تغییر درگاه پرداخت میتواند بخشهای مختلف سیستم را تحت تأثیر قرار دهد.
اما اگر یک Interface تعریف کنیم:
interface PaymentGateway
{
public function pay(float $amount): bool;
}
میتوانیم چند پیادهسازی مختلف داشته باشیم:
PaymentGateway
├── ZarinpalGateway
├── IDPayGateway
└── StripeGateway
بخش اصلی برنامه به جای وابستگی به یک Class مشخص، با PaymentGateway کار میکند.
این موضوع در پروژههای بزرگ اهمیت زیادی دارد.
# ساخت اولین Interface در PHP
یک Interface ساده ایجاد کنیم:
interface Animal
{
public function makeSound(): void;
}
اکنون یک Class ایجاد میکنیم:
class Dog implements Animal
{
public function makeSound(): void
{
echo "Woof!";
}
}
در اینجا Dog Interface مربوط به Animal را پیادهسازی کرده است.
برای پیادهسازی Interface از کلمه کلیدی:
implements
استفاده میکنیم.
# implements در PHP چیست؟
کلمه کلیدی implements مشخص میکند یک Class قصد دارد یک Interface را پیادهسازی کند.
مثلاً:
interface Logger
{
public function log(string $message): void;
}
class FileLogger implements Logger
{
public function log(string $message): void
{
echo $message;
}
}
در اینجا:
Logger
↓
FileLogger
Logger قرارداد را مشخص کرده و FileLogger آن قرارداد را پیادهسازی کرده است.
# اگر Methodهای Interface را پیادهسازی نکنیم چه اتفاقی میافتد؟
فرض کنید:
interface PaymentGateway
{
public function pay(float $amount): bool;
}
اما Class زیر را ایجاد کنیم:
class ZarinpalGateway implements PaymentGateway
{
}
این Class قرارداد Interface را کامل پیادهسازی نکرده است.
در نتیجه PHP خطا خواهد داد، مگر اینکه Class به شکل مناسب abstract باشد.
بنابراین هنگام پیادهسازی Interface باید Methodهای مورد نیاز آن را با امضای سازگار تعریف کنیم.
# یک مثال کامل از Interface
فرض کنید سیستم پرداخت داریم:
interface PaymentGateway
{
public function pay(float $amount): bool;
public function refund(string $transactionId): bool;
}
حالا درگاه اول:
class ZarinpalGateway implements PaymentGateway
{
public function pay(float $amount): bool
{
echo "Payment using Zarinpal";
return true;
}
public function refund(string $transactionId): bool
{
echo "Refund using Zarinpal";
return true;
}
}
درگاه دوم:
class StripeGateway implements PaymentGateway
{
public function pay(float $amount): bool
{
echo "Payment using Stripe";
return true;
}
public function refund(string $transactionId): bool
{
echo "Refund using Stripe";
return true;
}
}
هر دو Class یک قرارداد مشترک دارند، اما منطق داخلی آنها میتواند کاملاً متفاوت باشد.
# Interface فقط برای Method است؟
Interface میتواند شامل تعریف قراردادهایی برای Methodها و همچنین ساختارهای مرتبط با قرارداد باشد. در نسخههای جدید PHP قابلیتهای بیشتری نیز برای Interfaceها وجود دارد.
اما مهمترین کاربرد Interface در پروژههای روزمره PHP، تعریف قرارداد رفتاری Classها است.
مثلاً:
interface Exporter
{
public function export(array $data): string;
}
حالا:
class CsvExporter implements Exporter
{
public function export(array $data): string
{
return 'CSV data';
}
}
و:
class JsonExporter implements Exporter
{
public function export(array $data): string
{
return json_encode($data);
}
}
هر دو Exporter رفتار مشترک export() دارند.
# یک Class میتواند چند Interface داشته باشد؟
بله.
یکی از قابلیتهای مهم Interface این است که یک Class میتواند چند Interface را پیادهسازی کند.
مثلاً:
interface Loggable
{
public function log(): void;
}
interface Cacheable
{
public function cache(): void;
}
اکنون:
class ProductService implements Loggable, Cacheable
{
public function log(): void
{
echo "Logging...";
}
public function cache(): void
{
echo "Caching...";
}
}
در اینجا ProductService دو قرارداد مختلف را پیادهسازی کرده است.
# چرا Multiple Interface مفید است؟
فرض کنید یک سیستم فروشگاهی داریم.
یک Service ممکن است هم:
- قابلیت Log کردن داشته باشد.
- قابلیت Cache کردن داشته باشد.
- قابلیت Export کردن داشته باشد.
به جای ایجاد یک Class والد بزرگ، میتوانیم قراردادهای مختلف را با Interfaceهای جداگانه تعریف کنیم.
مثلاً:
ProductService
├── Loggable
├── Cacheable
└── Exportable
این طراحی میتواند نسبت به یک Hierarchy پیچیده انعطاف بیشتری داشته باشد.
# تفاوت Interface و Inheritance در PHP
در مقاله قبلی درباره Inheritance در PHP صحبت کردیم.
Inheritance با:
extends
انجام میشود.
Interface با:
implements
پیادهسازی میشود.
مثلاً:
class Dog extends Animal
{
}
در اینجا Dog از Animal ارثبری میکند.
اما:
class StripeGateway implements PaymentGateway
{
}
در اینجا StripeGateway قرارداد PaymentGateway را پیادهسازی میکند.
به زبان ساده:
Inheritance:
> این Object یک نوع از Object دیگر است.
Interface:
> این Class این قابلیت یا قرارداد را ارائه میدهد.
# Interface و Polymorphism
Interface یکی از ابزارهای مهم برای پیادهسازی Polymorphism است.
مثلاً:
interface PaymentGateway
{
public function pay(float $amount): bool;
}
دو پیادهسازی داریم:
class ZarinpalGateway implements PaymentGateway
{
public function pay(float $amount): bool
{
echo "Zarinpal payment";
return true;
}
}
و:
class StripeGateway implements PaymentGateway
{
public function pay(float $amount): bool
{
echo "Stripe payment";
return true;
}
}
اکنون میتوانیم یک Method بنویسیم که به جای وابستگی به یک Class مشخص، به Interface وابسته باشد:
function processPayment(
PaymentGateway $gateway,
float $amount
): bool {
return $gateway->pay($amount);
}
اکنون:
processPayment(
new ZarinpalGateway(),
500000
);
یا:
processPayment(
new StripeGateway(),
500000
);
هر دو قابل استفاده هستند.
این یکی از مهمترین مزایای Interface است.
# Type Hint با Interface
در PHP میتوانیم نوع پارامتر یک Method را Interface قرار دهیم.
مثلاً:
function sendPayment(
PaymentGateway $gateway
): bool {
return $gateway->pay(100000);
}
اکنون هر Objectی که PaymentGateway را پیادهسازی کرده باشد میتواند به این Method ارسال شود.
این کار باعث میشود Function ما به جای یک Implementation مشخص، به یک Contract وابسته باشد.
# Interface و Dependency Injection
Interface ارتباط بسیار نزدیکی با Dependency Injection دارد.
فرض کنید:
class OrderService
{
public function __construct(
private PaymentGateway $gateway
) {
}
public function pay(float $amount): bool
{
return $this->gateway->pay($amount);
}
}
حالا میتوانیم Gateway مورد نظر را هنگام ساخت Service ارسال کنیم:
$service = new OrderService(
new ZarinpalGateway()
);
یا:
$service = new OrderService(
new StripeGateway()
);
OrderService لازم نیست بداند جزئیات داخلی هر درگاه چگونه کار میکند.
فقط میداند Object دریافتشده باید قرارداد:
PaymentGateway
را رعایت کند.
این دقیقاً یکی از الگوهای مهم در طراحی نرمافزارهای قابل توسعه است.
# Interface و تستنویسی
Interfaceها در تستنویسی نیز بسیار مفید هستند.
فرض کنید:
class OrderService
{
public function __construct(
private PaymentGateway $gateway
) {
}
}
در تست میتوانیم یک Mock یا Fake مطابق قرارداد PaymentGateway ایجاد کنیم و بدون اتصال واقعی به درگاه، رفتار سیستم را بررسی کنیم.
این موضوع باعث میشود تستهای Application:
- سریعتر
- قابل کنترلتر
- مستقلتر از سرویسهای خارجی
باشند.
# تفاوت Interface و Abstract Class در PHP
Interface و Abstract Class شباهتهایی دارند، اما یکی نیستند.
Interface
Interface بیشتر برای تعریف قرارداد استفاده میشود.
interface PaymentGateway
{
public function pay(float $amount): bool;
}
Abstract Class
Abstract Class میتواند علاوه بر تعریف Methodهای abstract، دارای منطق و State مشترک نیز باشد.
مثلاً:
abstract class Payment
{
public function __construct(
protected float $amount
) {
}
abstract public function pay(): bool;
public function getAmount(): float
{
return $this->amount;
}
}
در اینجا Class پایه میتواند بخشی از منطق مشترک را نیز در اختیار فرزندان قرار دهد.
# Interface یا Abstract Class؛ کدام را انتخاب کنیم؟
اگر هدف اصلی شما تعریف یک Contract مشترک برای چند Class مستقل است، Interface انتخاب مناسبی است.
مثلاً:
PaymentGateway
├── Zarinpal
├── Stripe
└── PayPal
اما اگر چند Class علاوه بر قرارداد، State و منطق مشترک قابل استفاده مجدد دارند، Abstract Class ممکن است مناسبتر باشد.
البته در پروژههای واقعی ممکن است ترکیبی از Interface، Abstract Class و Composition استفاده شود.
# مثال واقعی؛ سیستم ارسال پیام
فرض کنید Application ما باید بتواند از چند سرویس پیام استفاده کند.
ابتدا Interface:
interface SmsProvider
{
public function send(
string $phone,
string $message
): bool;
}
حالا یک Provider:
class SmsProviderA implements SmsProvider
{
public function send(
string $phone,
string $message
): bool {
echo "Sending SMS using Provider A";
return true;
}
}
Provider دیگر:
class SmsProviderB implements SmsProvider
{
public function send(
string $phone,
string $message
): bool {
echo "Sending SMS using Provider B";
return true;
}
}
اکنون Service اصلی:
class NotificationService
{
public function __construct(
private SmsProvider $provider
) {
}
public function sendSms(
string $phone,
string $message
): bool {
return $this->provider->send(
$phone,
$message
);
}
}
اکنون NotificationService به یک Provider مشخص وابسته نیست.
این طراحی در صورت تغییر سرویس پیامک، انعطاف بیشتری دارد.
# مثال واقعی؛ Export کردن اطلاعات
فرض کنید Application ما باید اطلاعات کاربران را در چند فرمت خروجی دهد.
Interface:
interface Exporter
{
public function export(array $data): string;
}
JSON:
class JsonExporter implements Exporter
{
public function export(array $data): string
{
return json_encode($data);
}
}
CSV:
class CsvExporter implements Exporter
{
public function export(array $data): string
{
return implode(',', $data);
}
}
سپس:
function generateExport(
Exporter $exporter,
array $data
): string {
return $exporter->export($data);
}
اکنون سیستم ما میتواند Exporterهای مختلفی را بدون تغییر Function اصلی قبول کند.
# Interface در Laravel
اگر با Laravel کار میکنید، Interfaceها میتوانند در طراحی معماری Application نقش مهمی داشته باشند.
یک ساختار متداول میتواند شبیه این باشد:
app/
├── Contracts/
│ └── PaymentGateway.php
├── Services/
│ └── PaymentService.php
└── Payments/
├── ZarinpalGateway.php
└── StripeGateway.php
Interface:
namespace App\Contracts;
interface PaymentGateway
{
public function pay(float $amount): bool;
}
پیادهسازی:
namespace App\Payments;
use App\Contracts\PaymentGateway;
class ZarinpalGateway implements PaymentGateway
{
public function pay(float $amount): bool
{
// Payment logic
return true;
}
}
سپس میتوان وابستگی Interface را در Service مدیریت کرد.
# Binding کردن Interface در Laravel
یکی از کاربردهای مهم Interface در Laravel، استفاده از Service Container است.
مثلاً در یک Service Provider میتوان Interface را به Implementation مربوطه متصل کرد.
نمونه:
$this->app->bind(
PaymentGateway::class,
ZarinpalGateway::class
);
اکنون وقتی Laravel به یک Dependency از نوع:
PaymentGateway
نیاز داشته باشد، میتواند Implementation مربوطه را Resolve کند.
این موضوع در پروژههایی که چند Implementation مختلف دارند بسیار مفید است.
# Interface در پروژههای بزرگ Laravel
فرض کنید یک سیستم فروشگاهی دارید:
PaymentGateway
├── ZarinpalGateway
├── IDPayGateway
└── StripeGateway
یا سیستم ارسال:
ShippingProvider
├── PostProvider
├── TipaxProvider
└── CustomShippingProvider
یا سرویس ذخیره فایل:
FileStorage
├── LocalStorage
├── S3Storage
└── CustomStorage
در همه این موارد یک Interface میتواند قرارداد مشترک را مشخص کند.
در نتیجه Service اصلی برنامه مجبور نیست به جزئیات Implementation وابسته باشد.
# Interface و اصل Dependency Inversion
Interfaceها ارتباط نزدیکی با یکی از اصول مهم SOLID یعنی:
Dependency Inversion Principle
دارند.
ایده اصلی این اصل این است که بخشهای سطح بالا نباید به جزئیات پیادهسازی وابستگی مستقیم داشته باشند.
به جای:
class OrderService
{
private ZarinpalGateway $gateway;
}
میتوانیم داشته باشیم:
class OrderService
{
public function __construct(
private PaymentGateway $gateway
) {
}
}
در حالت دوم، OrderService به Contract وابسته است، نه به یک Implementation خاص.
مقاله اختصاصی SOLID در PHP این موضوع را عمیقتر بررسی خواهد کرد.
# اشتباهات رایج در استفاده از Interface
۱. ساخت Interface برای هر Class بدون دلیل
لازم نیست برای هر Class یک Interface ایجاد کنید.
Interface زمانی ارزشمند است که واقعاً چند Implementation، یک Contract مستقل یا یک Boundary معماری داشته باشید.
۲. قرار دادن منطق زیاد در Interface
هدف Interface معمولاً تعریف قرارداد است، نه قرار دادن منطق اصلی Business Application.
۳. نامگذاری نامناسب
نام Interface باید مفهوم Contract را منتقل کند.
مثلاً:
PaymentGateway
نام مناسبی است.
اما نامهایی مانند:
MyInterface
اطلاعات مفیدی درباره مسئولیت آن نمیدهند.
۴. Interfaceهای بسیار بزرگ
اگر یک Interface دهها Method غیرمرتبط داشته باشد، احتمالاً طراحی مناسبی ندارد.
این موضوع با Interface Segregation Principle در SOLID ارتباط دارد.
# Interface Segregation چیست؟
یکی از اصول SOLID میگوید Classها نباید مجبور شوند به Interfaceهایی وابسته باشند که به آنها نیاز ندارند.
مثلاً یک Interface بزرگ:
interface Worker
{
public function code(): void;
public function design(): void;
public function write(): void;
public function manageServer(): void;
}
ممکن است برای بسیاری از Classها بیش از حد بزرگ باشد.
گاهی بهتر است قراردادها را جدا کنیم:
interface Coder
{
public function code(): void;
}
interface Designer
{
public function design(): void;
}
interface Writer
{
public function write(): void;
}
این طراحی انعطافپذیرتر است.
# بهترین روش استفاده از Interface در PHP
برای استفاده حرفهای از Interface این نکات را رعایت کنید:
۱. Interface را بر اساس Contract طراحی کنید
به جای اینکه صرفاً یک نسخه از Class را در قالب Interface قرار دهید، رفتار مورد نیاز را مشخص کنید.
۲. Interface را کوچک نگه دارید
هر Interface بهتر است مسئولیت مشخصی داشته باشد.
۳. به Abstraction وابسته باشید
در بخشهای مناسب Application به Interface وابسته شوید، نه Implementation.
۴. از Dependency Injection استفاده کنید
Dependencyها را از بیرون دریافت کنید.
۵. برای چند Implementation از Interface استفاده کنید
اگر قرار است چند Provider، Gateway یا Service جایگزین یکدیگر شوند، Interface گزینه بسیار مناسبی است.
# جمعبندی Interface در PHP
Interface در PHP ابزاری برای تعریف قرارداد بین Classها است.
با استفاده از:
interface
میتوان قرارداد را تعریف کرد و با:
implements
آن را در یک Class پیادهسازی کرد.
مثلاً:
interface PaymentGateway
{
public function pay(float $amount): bool;
}
و:
class ZarinpalGateway implements PaymentGateway
{
public function pay(float $amount): bool
{
return true;
}
}
مزیت مهم Interface این است که بخشهای مختلف Application میتوانند به جای وابستگی به یک Implementation مشخص، به یک Contract وابسته باشند.
این موضوع در کنار:
- Dependency Injection
- Polymorphism
- Service Container
- SOLID
- تستنویسی
- معماری نرمافزار
اهمیت بسیار زیادی پیدا میکند.
اگر در حال یادگیری PHP برای ورود به توسعه حرفهای Laravel هستید، یادگیری Interface یکی از قدمهای مهم بعد از Class، Object و Inheritance است.
در مقاله بعدی این مجموعه، سراغ Trait در PHP میرویم و بررسی میکنیم چگونه میتوانیم رفتارهای مشترک را بدون ایجاد زنجیرههای پیچیده Inheritance بین چند Class به اشتراک بگذاریم.
# سوالات متداول Interface در PHP
Interface در PHP چیست؟
Interface در PHP یک قرارداد است که مشخص میکند Class پیادهساز باید چه رفتارهایی را ارائه دهد.
برای ساخت Interface در PHP از چه کلمهای استفاده میشود؟
از کلمه کلیدی interface استفاده میشود:
interface PaymentGateway
{
}
implements در PHP چیست؟
implements برای پیادهسازی یک Interface توسط Class استفاده میشود:
class ZarinpalGateway implements PaymentGateway
{
}
آیا یک Class میتواند چند Interface داشته باشد؟
بله. یک Class میتواند چند Interface را با استفاده از implements پیادهسازی کند:
class Service implements Loggable, Cacheable
{
}
تفاوت Interface و Abstract Class چیست؟
Interface عمدتاً برای تعریف Contract استفاده میشود، در حالی که Abstract Class میتواند علاوه بر Methodهای abstract، State و منطق مشترک نیز داشته باشد.
آیا Interface در Laravel کاربرد دارد؟
بله. Interfaceها در Laravel میتوانند برای تعریف Contract، Dependency Injection، Service Container، چند Implementation مختلف و معماری قابل توسعه استفاده شوند.
آیا برای هر Class باید Interface بسازیم؟
خیر. ساخت Interface باید دلیل معماری مشخصی داشته باشد؛ مثلاً چند Implementation، یک Boundary مشخص یا نیاز به Abstraction.
Interface چه ارتباطی با SOLID دارد؟
Interface با اصول مختلف SOLID، بهخصوص Dependency Inversion Principle و Interface Segregation Principle، ارتباط نزدیکی دارد.
# مقالات مرتبط
برای ایجاد ساختار Topic Cluster و لینکسازی داخلی، این مقاله را به صفحات زیر متصل کنید:
- OOP در PHP
- Class و Object در PHP
- Inheritance در PHP
- Trait در PHP
- Abstract Class در PHP
- Dependency Injection در PHP
- SOLID در PHP
- Design Pattern در PHP
- Composer چیست؟
- Autoload در PHP
و در ابتدای مقاله یا بخش پایانی، یک لینک طبیعی به صفحه Pillar:
آموزش برنامه نویسی وب از صفر تا پیشرفته؛ PHP، Laravel، MySQL و توسعه وب
قرار دهید.





