سی ام اس نویسسی ام اس نویسیاد بگیر، سیستم خودتو بنویس
مجلهتماس با ما
سی ام اس نویسسی ام اس نویس

CMS نویس مرجعی برای آموزش برنامه نویسی وب و PHP، توسعه افزونه‌های اختصاصی وردپرس، طراحی ورک‌فلو و اتوماسیون با n8n و توسعه CMS های اختصاصی است. هدف ما ارائه آموزش‌های کاربردی و راهکارهای حرفه‌ای برای توسعه‌دهندگان، کسب‌وکارها و علاقه‌مندان به دنیای برنامه‌نویسی است.

پیوندهای سریع
محصولات فیزیکیمحصولات دیجیتالدوره‌های آموزشی
سی ام اس نویس
مجله سی ام اس نویستماس با ماپنل کاربری
سی ام اس نویس — تمامی حقوق برای سی ام اس نویس محفوظ است. © 1406 تماس با ما09307711941
Dependency Injection در PHP چیست؟ آموزش تزریق وابستگی با مثال عملی

Dependency Injection در PHP چیست؟ آموزش تزریق وابستگی با مثال عملی

ممدیر کل سیستم ۱۹ شهریور ۱۴۰۵ ۲۱ دقیقه مطالعه ۳ بازدید
Dependency Injection در PHP چیست؟ آموزش تزریق وابستگی با مثال عملی

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

فرض کنید یک کلاس برای ارسال ایمیل داریم:


class UserService

{

    public function sendWelcomeEmail()

    {

        $mailer = new Mailer();



        $mailer->send(

            'user@example.com',

            'Welcome'

        );

    }

}

در نگاه اول این کد کاملاً قابل استفاده است، اما UserService مستقیماً به Mailer وابسته شده است.

اگر بعداً بخواهیم:

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

کد ما به مشکل می‌خورد.

اینجاست که مفهوم Dependency Injection یا تزریق وابستگی اهمیت پیدا می‌کند.

در این مقاله از مجموعه آموزش PHP در سی ام اس نویس، ابتدا مفهوم Dependency را بررسی می‌کنیم، سپس Dependency Injection را با مثال‌های ساده و واقعی یاد می‌گیریم و در ادامه به سراغ Constructor Injection، Interface، تست‌پذیری و کاربرد DI در Laravel می‌رویم.


# Dependency در PHP چیست؟

قبل از اینکه Dependency Injection را یاد بگیریم، ابتدا باید بدانیم Dependency چیست.

Dependency یعنی یک کلاس برای انجام وظیفه خودش به کلاس یا سرویس دیگری نیاز داشته باشد.

مثلاً:


class OrderService

{

    public function createOrder()

    {

        $payment = new PaymentService();



        $payment->pay();

    }

}

در این مثال:


OrderService

      ↓

PaymentService

کلاس OrderService به PaymentService وابستگی دارد.

یعنی PaymentService یک Dependency برای OrderService است.


# مشکل ایجاد Dependency داخل کلاس چیست؟

کد زیر را در نظر بگیرید:


class OrderService

{

    public function createOrder()

    {

        $payment = new PaymentService();



        $payment->pay();

    }

}

مشکل اصلی این است که OrderService خودش تصمیم گرفته که از PaymentService استفاده کند.

حالا فرض کنید سه روش پرداخت داریم:


PaymentService

BankPayment

WalletPayment

اگر کد را به شکل زیر نوشته باشیم:


class OrderService

{

    public function createOrder()

    {

        $payment = new BankPayment();



        $payment->pay();

    }

}

تغییر روش پرداخت نیازمند تغییر OrderService است.

این وابستگی شدید، Tight Coupling نام دارد.


# Tight Coupling چیست؟

Tight Coupling یا وابستگی شدید زمانی اتفاق می‌افتد که یک کلاس مستقیماً به پیاده‌سازی مشخص یک کلاس دیگر وابسته باشد.

مثلاً:


class OrderService

{

    public function __construct()

    {

        $this->payment = new BankPayment();

    }

}

در اینجا OrderService مستقیماً به BankPayment وابسته است.

اگر بخواهیم WalletPayment استفاده کنیم، باید کلاس را تغییر دهیم.

این موضوع در پروژه‌های بزرگ باعث افزایش پیچیدگی و کاهش انعطاف‌پذیری می‌شود.


# Dependency Injection چیست؟

Dependency Injection یا DI روشی برای مدیریت وابستگی بین کلاس‌ها است که در آن وابستگی مورد نیاز یک کلاس، به جای اینکه داخل آن ساخته شود، از بیرون به آن داده می‌شود.

به جای:


class OrderService

{

    public function __construct()

    {

        $this->payment = new BankPayment();

    }

}

می‌توانیم بنویسیم:


class OrderService

{

    public function __construct(

        private BankPayment $payment

    ) {

    }

}

حالا BankPayment از بیرون به OrderService داده می‌شود:


$payment = new BankPayment();



$orderService = new OrderService($payment);

این یعنی وابستگی تزریق شده است.


# یک مثال بسیار ساده از Dependency Injection

فرض کنید یک کلاس داریم:


class Logger

{

    public function log(string $message): void

    {

        echo $message;

    }

}

و کلاس دیگری که به Logger نیاز دارد:


class UserService

{

    public function __construct(

        private Logger $logger

    ) {

    }



    public function createUser(): void

    {

        $this->logger->log('User created');

    }

}

حالا:


$logger = new Logger();



$userService = new UserService($logger);



$userService->createUser();

در اینجا:


Logger

   ↓

UserService

Logger از بیرون به UserService تزریق شده است.


# چرا Dependency Injection مهم است؟

DI چند مزیت بسیار مهم دارد:

کاهش وابستگی بین کلاس‌ها

کلاس‌ها کمتر به پیاده‌سازی مشخص وابسته می‌شوند.

افزایش تست‌پذیری

می‌توانیم Dependency واقعی را با یک Mock یا Fake جایگزین کنیم.

افزایش قابلیت تغییر

تعویض سرویس‌ها ساده‌تر می‌شود.

استفاده مجدد از کلاس‌ها

کلاس‌ها به محیط یا پیاده‌سازی خاصی وابسته نمی‌شوند.

معماری تمیزتر

مسئولیت ساخت Object از مسئولیت استفاده از آن جدا می‌شود.


# انواع Dependency Injection در PHP

به طور کلی چند روش رایج برای تزریق Dependency وجود دارد:

  1. Constructor Injection
  2. Setter Injection
  3. Method Injection
  4. Property Injection

در PHP و فریم‌ورک‌هایی مثل Laravel، Constructor Injection یکی از مهم‌ترین و رایج‌ترین روش‌ها است.


# Constructor Injection در PHP

در Constructor Injection، وابستگی هنگام ساخت Object از طریق Constructor دریافت می‌شود.

مثلاً:


class Mailer

{

    public function send(string $email): void

    {

        echo "Sending email to {$email}";

    }

}

کلاس وابسته:


class UserService

{

    public function __construct(

        private Mailer $mailer

    ) {

    }



    public function register(): void

    {

        $this->mailer->send('user@example.com');

    }

}

استفاده:


$mailer = new Mailer();



$userService = new UserService($mailer);



$userService->register();

در اینجا Mailer از طریق Constructor تزریق شده است.


# چرا Constructor Injection انتخاب خوبی است؟

یکی از مزایای مهم Constructor Injection این است که Dependency مورد نیاز کلاس از همان ابتدا مشخص است.

مثلاً:


class OrderService

{

    public function __construct(

        private PaymentService $payment,

        private Logger $logger

    ) {

    }

}

با دیدن Constructor بلافاصله متوجه می‌شویم:


OrderService

 ├── PaymentService

 └── Logger

به این ترتیب وابستگی‌های اصلی کلاس واضح هستند.


# Method Injection چیست؟

در Method Injection، Dependency مستقیماً به یک متد داده می‌شود.

مثلاً:


class ReportService

{

    public function generate(Logger $logger): void

    {

        $logger->log('Report generated');

    }

}

استفاده:


$logger = new Logger();



$service = new ReportService();



$service->generate($logger);

این روش زمانی مفید است که Dependency فقط برای یک عملیات خاص مورد نیاز باشد.


# Setter Injection چیست؟

در Setter Injection، وابستگی از طریق یک متد Setter تنظیم می‌شود.

مثلاً:


class UserService

{

    private Logger $logger;



    public function setLogger(Logger $logger): void

    {

        $this->logger = $logger;

    }

}

سپس:


$service = new UserService();



$service->setLogger(

    new Logger()

);

این روش در بعضی سناریوها مفید است، اما اگر Dependency برای کارکرد اصلی کلاس ضروری باشد، Constructor Injection معمولاً انتخاب بهتری است.


# Property Injection چیست؟

در Property Injection، Dependency مستقیماً داخل Property قرار می‌گیرد.

مثلاً:


class UserService

{

    public Logger $logger;

}

سپس:


$service = new UserService();



$service->logger = new Logger();

این روش معمولاً برای Dependencyهای ضروری انتخاب خوبی نیست، زیرا ممکن است Object قبل از مقداردهی Dependency مورد استفاده قرار گیرد.

به همین دلیل، برای وابستگی‌های ضروری، Constructor Injection معمولاً انتخاب امن‌تر و واضح‌تری است.


# Dependency Injection با Interface

قدرت واقعی Dependency Injection زمانی بیشتر مشخص می‌شود که به جای وابستگی مستقیم به یک Class، به یک Interface وابسته شویم.

مثلاً:


interface PaymentInterface

{

    public function pay(float $amount): bool;

}

حالا:


class BankPayment implements PaymentInterface

{

    public function pay(float $amount): bool

    {

        echo 'Bank payment';



        return true;

    }

}

و:


class WalletPayment implements PaymentInterface

{

    public function pay(float $amount): bool

    {

        echo 'Wallet payment';



        return true;

    }

}

اکنون OrderService را به Interface وابسته می‌کنیم:


class OrderService

{

    public function __construct(

        private PaymentInterface $payment

    ) {

    }



    public function checkout(float $amount): bool

    {

        return $this->payment->pay($amount);

    }

}

حالا می‌توانیم هر پیاده‌سازی سازگار را تزریق کنیم.


$order = new OrderService(

    new BankPayment()

);



$order->checkout(500000);

یا:


$order = new OrderService(

    new WalletPayment()

);



$order->checkout(500000);

کلاس OrderService دیگر به BankPayment یا WalletPayment وابسته نیست.

بلکه به قرارداد زیر وابسته است:


PaymentInterface


# Dependency Inversion چه ارتباطی با Dependency Injection دارد؟

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

Dependency Injection یک تکنیک برای وارد کردن Dependency به یک کلاس است.

اما Dependency Inversion Principle یکی از اصول SOLID است که درباره نحوه وابستگی ماژول‌ها صحبت می‌کند.

به زبان ساده، به جای اینکه منطق اصلی برنامه به جزئیات خاص وابسته باشد، بهتر است به abstraction وابسته شود.

مثلاً:


class OrderService

{

    public function __construct(

        private PaymentInterface $payment

    ) {

    }

}

در اینجا OrderService به Interface وابسته است، نه به یک پیاده‌سازی خاص.

این موضوع زمینه را برای یادگیری SOLID در PHP آماده می‌کند.


# بدون Dependency Injection چه اتفاقی می‌افتد؟

فرض کنید:


class OrderService

{

    public function checkout()

    {

        $payment = new BankPayment();



        return $payment->pay(500000);

    }

}

اگر فردا بخواهیم از کیف پول استفاده کنیم:


$payment = new WalletPayment();

باید OrderService را تغییر دهیم.

اما با DI:


class OrderService

{

    public function __construct(

        private PaymentInterface $payment

    ) {

    }



    public function checkout(): bool

    {

        return $this->payment->pay(500000);

    }

}

روش پرداخت از بیرون تعیین می‌شود.


# Dependency Injection و تست‌نویسی

یکی از بزرگ‌ترین مزایای DI، افزایش Testability یا تست‌پذیری است.

فرض کنید:


interface PaymentInterface

{

    public function pay(float $amount): bool;

}

در برنامه واقعی:


class BankPayment implements PaymentInterface

{

    public function pay(float $amount): bool

    {

        // اتصال واقعی به درگاه



        return true;

    }

}

اما هنگام تست نمی‌خواهیم واقعاً به درگاه پرداخت وصل شویم.

می‌توانیم یک Fake بسازیم:


class FakePayment implements PaymentInterface

{

    public function pay(float $amount): bool

    {

        return true;

    }

}

حالا:


$order = new OrderService(

    new FakePayment()

);

به این ترتیب می‌توانیم منطق OrderService را بدون اتصال واقعی به درگاه تست کنیم.

این یکی از دلایل مهم استفاده از Dependency Injection در پروژه‌های حرفه‌ای است.


# Dependency Injection Container چیست؟

در پروژه‌های کوچک می‌توانیم Dependencyها را خودمان ایجاد و تزریق کنیم:


$payment = new BankPayment();



$order = new OrderService($payment);

اما در پروژه‌های بزرگ، تعداد Dependencyها زیاد می‌شود.

مثلاً:


Controller

    ↓

Service

    ↓

Repository

    ↓

Database

اگر بخواهیم همه این Objectها را دستی بسازیم، مدیریت آن‌ها سخت می‌شود.

اینجاست که مفهوم Dependency Injection Container مطرح می‌شود.

Container وظیفه دارد Dependencyهای مورد نیاز کلاس‌ها را پیدا و Resolve کند.


# یک مثال ساده از Container

فرض کنید:


class Logger

{

}

و:


class UserService

{

    public function __construct(

        private Logger $logger

    ) {

    }

}

Container می‌تواند متوجه شود که UserService به Logger نیاز دارد و Logger را برای آن ایجاد کند.

در فریم‌ورک‌هایی مثل Laravel این فرآیند بسیار گسترده‌تر و قدرتمندتر انجام می‌شود.


# Dependency Injection در Laravel

Laravel یکی از نمونه‌های معروف استفاده گسترده از Dependency Injection است.

مثلاً می‌توانیم یک Service ایجاد کنیم:


class UserService

{

    public function create(): void

    {

        // ...

    }

}

و آن را در Controller تزریق کنیم:


class UserController

{

    public function __construct(

        private UserService $userService

    ) {

    }



    public function store()

    {

        $this->userService->create();

    }

}

Laravel می‌تواند Dependency مورد نیاز Controller را از طریق Service Container مدیریت کند.

این یعنی لازم نیست در Controller بنویسیم:


$this->userService = new UserService();

در عوض Dependency در Constructor تعریف می‌شود.


# Dependency Injection در Laravel با Interface

یکی از کاربردهای قدرتمند Container لاراول زمانی است که به Interface وابسته باشیم.

مثلاً:


interface PaymentGateway

{

    public function pay(int $amount): bool;

}

پیاده‌سازی:


class ZarinpalGateway implements PaymentGateway

{

    public function pay(int $amount): bool

    {

        // Zarinpal API



        return true;

    }

}

سرویس:


class PaymentService

{

    public function __construct(

        private PaymentGateway $gateway

    ) {

    }



    public function pay(int $amount): bool

    {

        return $this->gateway->pay($amount);

    }

}

حالا می‌توانیم Interface را در Container به یک پیاده‌سازی مشخص Bind کنیم.

برای مثال:


$this->app->bind(

    PaymentGateway::class,

    ZarinpalGateway::class

);

پس هر جا Laravel به PaymentGateway نیاز داشته باشد، می‌تواند ZarinpalGateway را Resolve کند.

این الگو در پروژه‌هایی که چند Provider یا Driver دارند بسیار کاربردی است.


# تفاوت Dependency Injection و Dependency Injection Container

این دو اصطلاح را نباید با یکدیگر اشتباه بگیریم.

Dependency Injection

یک روش برای وارد کردن Dependency به یک کلاس است.

مثلاً:


class UserService

{

    public function __construct(

        private Logger $logger

    ) {

    }

}

Dependency Injection Container

ابزاری است که ایجاد و Resolve کردن Dependencyها را مدیریت می‌کند.

به صورت ساده:


Dependency Injection

        ↓

روش تزریق Dependency



Container

        ↓

مدیریت و Resolve کردن Dependencyها

Laravel هر دو مفهوم را در معماری خود به شکل گسترده استفاده می‌کند.


# Dependency Injection و Service Container چه مزیتی دارند؟

فرض کنید یک کلاس داریم:


class OrderService

{

    public function __construct(

        private PaymentInterface $payment,

        private Logger $logger,

        private OrderRepository $repository

    ) {

    }

}

اگر بخواهیم این Object را دستی بسازیم، باید تمام وابستگی‌های آن را نیز ایجاد کنیم.

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

این موضوع در پروژه‌های بزرگ باعث کاهش پیچیدگی Object Creation می‌شود.


# مثال واقعی: ارسال پیامک

فرض کنید یک سایت داریم و می‌خواهیم برای کاربران پیامک ارسال کنیم.

ابتدا Interface:


interface SmsServiceInterface

{

    public function send(

        string $mobile,

        string $message

    ): bool;

}

پیاده‌سازی اول:


class MelipayamakService implements SmsServiceInterface

{

    public function send(

        string $mobile,

        string $message

    ): bool {

        // API request



        return true;

    }

}

پیاده‌سازی دوم:


class SmsIrService implements SmsServiceInterface

{

    public function send(

        string $mobile,

        string $message

    ): bool {

        // API request



        return true;

    }

}

حالا سرویس کاربر:


class UserService

{

    public function __construct(

        private SmsServiceInterface $sms

    ) {

    }



    public function verify(

        string $mobile

    ): void {

        $this->sms->send(

            $mobile,

            'کد تأیید شما 1234 است.'

        );

    }

}

مزیت این ساختار چیست؟

اگر فردا سرویس پیامکی را تغییر دهیم، لازم نیست UserService را تغییر دهیم.

فقط پیاده‌سازی Interface تغییر می‌کند.


# Dependency Injection و Loose Coupling

هدف اصلی DI فقط این نیست که کد را کوتاه‌تر کنیم.

یکی از اهداف اصلی آن ایجاد Loose Coupling یا وابستگی کمتر بین اجزای برنامه است.

مثلاً:


بدون DI:



OrderService

      ↓

BankPayment

اما:


با DI + Interface:



OrderService

      ↓

PaymentInterface

      ↑

 ┌────┴─────┐

 │          │

Bank      Wallet

در ساختار دوم، OrderService لازم نیست بداند دقیقاً چه کلاس‌هایی پشت Interface قرار دارند.

این موضوع انعطاف معماری را افزایش می‌دهد.


# Dependency Injection و Single Responsibility Principle

DI به اجرای بهتر اصول SOLID کمک می‌کند.

یکی از این اصول Single Responsibility Principle یا SRP است.

فرض کنید:


class UserService

{

    public function register()

    {

        $db = new Database();

        $mailer = new Mailer();

        $logger = new Logger();



        // register user

        // send email

        // log

    }

}

در اینجا کلاس هم مسئول ساخت Dependencyها شده و هم مسئول منطق کسب‌وکار.

با DI:


class UserService

{

    public function __construct(

        private Database $db,

        private Mailer $mailer,

        private Logger $logger

    ) {

    }



    public function register()

    {

        // business logic

    }

}

ساخت Dependencyها از منطق اصلی کلاس جدا شده است.


# آیا Dependency Injection فقط مخصوص PHP است؟

خیر.

Dependency Injection یک مفهوم عمومی در مهندسی نرم‌افزار است و در زبان‌ها و فریم‌ورک‌های مختلف استفاده می‌شود.

اما در PHP، مخصوصاً هنگام کار با فریم‌ورک‌هایی مانند Laravel، اهمیت آن بسیار بیشتر می‌شود؛ زیرا پروژه‌های بزرگ معمولاً تعداد زیادی Service، Repository، Interface و Component دارند.


# اشتباهات رایج در Dependency Injection

۱. ایجاد Dependency با new داخل کلاس

مثلاً:


class OrderService

{

    public function process()

    {

        $payment = new BankPayment();

    }

}

اگر BankPayment یک Dependency واقعی است، بهتر است وابستگی آن به شکل مناسبی مدیریت شود.


۲. استفاده بیش از حد از Dependency Injection

اینکه هر چیزی را به Constructor اضافه کنیم الزاماً طراحی خوبی نیست.

مثلاً:


class UserService

{

    public function __construct(

        private A $a,

        private B $b,

        private C $c,

        private D $d,

        private E $e,

        private F $f,

        private G $g

    ) {

    }

}

اگر Constructor بیش از حد بزرگ شود، ممکن است کلاس بیش از اندازه مسئولیت داشته باشد.

در این حالت بهتر است معماری کلاس را بررسی کنیم.


۳. اشتباه گرفتن DI با Interface

Interface خودش Dependency Injection نیست.

Interface یک قرارداد است.

مثلاً:


interface PaymentInterface

{

    public function pay(float $amount): bool;

}

اما این:


class OrderService

{

    public function __construct(

        private PaymentInterface $payment

    ) {

    }

}

نمونه‌ای از Dependency Injection است.


# بهترین روش استفاده از Dependency Injection

برای پروژه‌های PHP چند اصل کاربردی را در نظر بگیرید:

Dependencyهای ضروری را از Constructor دریافت کنید

مثلاً:


public function __construct(

    private Logger $logger

) {

}

در صورت نیاز به انعطاف، به Interface وابسته شوید

مثلاً:


private PaymentInterface $payment

به جای:


private BankPayment $payment

ساخت Object را از استفاده از Object جدا کنید

تا جای ممکن کلاس‌ها نباید مسئول ساخت تمام Dependencyهای خودشان باشند.

Constructor را بیش از حد بزرگ نکنید

Constructor بسیار بزرگ می‌تواند نشانه طراحی نامناسب باشد.

DI را به خاطر DI استفاده نکنید

اگر یک Dependency ساده و کاملاً داخلی است و هیچ نیازی به تعویض یا تست جداگانه ندارد، پیچیده کردن معماری ممکن است ارزش نداشته باشد.


# Dependency Injection چه زمانی ضروری‌تر می‌شود؟

DI در پروژه‌های بزرگ اهمیت بیشتری پیدا می‌کند؛ مخصوصاً وقتی:

  • چند پیاده‌سازی از یک سرویس دارید.
  • تست‌نویسی اهمیت دارد.
  • پروژه چند ماژول دارد.
  • سرویس‌های خارجی استفاده می‌کنید.
  • سیستم پرداخت دارید.
  • چند SMS Provider دارید.
  • چند Storage دارید.
  • چند Notification Channel دارید.
  • معماری Service Layer دارید.
  • از Repository Pattern استفاده می‌کنید.
  • پروژه Laravel یا یک Framework بزرگ دارید.

# یک مثال نهایی از معماری مناسب

فرض کنید سیستم فروشگاه شما به یک سرویس پرداخت نیاز دارد.

ابتدا قرارداد:


interface PaymentGateway

{

    public function pay(int $amount): bool;

}

پیاده‌سازی:


class BankGateway implements PaymentGateway

{

    public function pay(int $amount): bool

    {

        // connect to bank



        return true;

    }

}

سرویس:


class CheckoutService

{

    public function __construct(

        private PaymentGateway $gateway

    ) {

    }



    public function checkout(int $amount): bool

    {

        return $this->gateway->pay($amount);

    }

}

در بخش Composition Root یا Container برنامه تصمیم می‌گیریم:


PaymentGateway

       ↓

BankGateway

حالا اگر در آینده درگاه دیگری اضافه کنیم:


PaymentGateway

       ↓

 ┌─────┴──────┐

 │            │

Bank        Wallet

CheckoutService نیازی به تغییر ندارد.

این همان انعطاف‌پذیری‌ای است که Dependency Injection به معماری برنامه می‌دهد.


# تفاوت Dependency Injection با Dependency Inversion

این دو مفهوم بسیار شبیه به نظر می‌رسند، اما یکی نیستند.

Dependency Injection یک تکنیک است.

Dependency Inversion Principle یک اصل طراحی از SOLID است.

مثلاً وقتی می‌نویسیم:


class CheckoutService

{

    public function __construct(

        private PaymentInterface $payment

    ) {

    }

}

از Dependency Injection استفاده کرده‌ایم.

همزمان، اگر طراحی ما باعث شود CheckoutService به abstraction وابسته باشد و نه یک implementation خاص، در راستای Dependency Inversion Principle نیز حرکت کرده‌ایم.


# آیا Dependency Injection باعث پیچیده شدن کد می‌شود؟

در پروژه‌های کوچک ممکن است در نگاه اول کمی کد بیشتری ایجاد کند.

مثلاً به جای:


$mailer = new Mailer();

ممکن است بنویسیم:


public function __construct(

    private Mailer $mailer

) {

}

اما با بزرگ‌تر شدن پروژه، مزایای آن بیشتر مشخص می‌شود.

به خصوص زمانی که نیاز داشته باشیم:

  • پیاده‌سازی را تغییر دهیم.
  • تست بنویسیم.
  • Mock ایجاد کنیم.
  • چند Provider داشته باشیم.
  • معماری پروژه را توسعه دهیم.

بنابراین DI بیشتر یک ابزار برای مدیریت پیچیدگی است.


# جمع‌بندی Dependency Injection در PHP

Dependency Injection یکی از مفاهیم مهم در برنامه‌نویسی شی‌گرا و طراحی نرم‌افزار است.

به جای اینکه یک کلاس Dependencyهای خودش را مستقیماً ایجاد کند:


class OrderService

{

    public function process()

    {

        $payment = new BankPayment();

    }

}

آن Dependency را از بیرون دریافت می‌کنیم:


class OrderService

{

    public function __construct(

        private PaymentInterface $payment

    ) {

    }

}

این کار باعث می‌شود:

  • وابستگی بین کلاس‌ها کاهش پیدا کند.
  • کد تست‌پذیرتر شود.
  • تعویض پیاده‌سازی‌ها ساده‌تر شود.
  • معماری پروژه انعطاف بیشتری داشته باشد.
  • مسئولیت ساخت Object از منطق کسب‌وکار جدا شود.

در پروژه‌های بزرگ‌تر، Dependency Injection معمولاً همراه با Interface، Service Container، SOLID، Repository Pattern و Service Layer استفاده می‌شود.

اگر می‌خواهید وارد توسعه حرفه‌ای PHP و Laravel شوید، درک صحیح DI یکی از پایه‌های مهم برای فهم معماری پروژه‌های بزرگ است.


# سوالات متداول Dependency Injection در PHP

Dependency Injection در PHP چیست؟

Dependency Injection روشی برای وارد کردن وابستگی مورد نیاز یک کلاس از بیرون است، به جای اینکه کلاس خودش آن Dependency را ایجاد کند.

ساده‌ترین روش Dependency Injection در PHP چیست؟

یکی از رایج‌ترین روش‌ها Constructor Injection است:


class UserService

{

    public function __construct(

        private Logger $logger

    ) {

    }

}

Constructor Injection چیست؟

در Constructor Injection، Dependency هنگام ساخت Object از طریق Constructor به کلاس داده می‌شود.

آیا Dependency Injection فقط در Laravel استفاده می‌شود؟

خیر. Dependency Injection یک مفهوم عمومی در طراحی نرم‌افزار است و می‌توان آن را در PHP خام و بسیاری از زبان‌ها و Frameworkها استفاده کرد.

Dependency Injection Container چیست؟

Container سیستمی برای مدیریت، ایجاد و Resolve کردن Dependencyهای Objectها است. Laravel Service Container نمونه‌ای از چنین سیستمی است.

تفاوت Dependency Injection و Dependency Inversion چیست؟

Dependency Injection یک تکنیک برای تزریق وابستگی است، در حالی که Dependency Inversion Principle یکی از اصول SOLID برای طراحی وابستگی بین ماژول‌ها است.

چرا Dependency Injection باعث افزایش تست‌پذیری می‌شود؟

زیرا می‌توانیم Dependency واقعی را هنگام تست با یک Mock، Fake یا Stub جایگزین کنیم و بدون اجرای سرویس واقعی، منطق کلاس موردنظر را تست کنیم.

آیا همیشه باید از Dependency Injection استفاده کنیم؟

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


# پیشنهاد لینک‌سازی داخلی

برای اینکه این مقاله در ساختار Topic Cluster سایت شما جایگاه مناسبی داشته باشد، پیشنهاد می‌کنم لینک‌ها را به شکل زیر قرار دهید:

لینک به مقاله‌های قبلی

  • Class و Object در PHP → با انکرتکست Class و Object در PHP
  • Inheritance در PHP → با انکرتکست ارث‌بری در PHP
  • Interface در PHP → با انکرتکست Interface در PHP
  • Abstract Class در PHP → با انکرتکست Abstract Class در PHP
  • Trait در PHP → با انکرتکست Trait در PHP

لینک به مقاله‌های بعدی

  • SOLID در PHP → با انکرتکست اصول SOLID در PHP
  • Design Pattern در PHP → با انکرتکست Design Pattern در PHP
  • MVC چیست؟ → با انکرتکست معماری MVC در PHP

لینک به Pillar

در مقدمه یا جمع‌بندی یک لینک به:

آموزش برنامه نویسی وب از صفر تا پیشرفته؛ PHP، Laravel، MySQL و توسعه وب

قرار دهید.

جایگاه این مقاله در کلاستر


آموزش برنامه نویسی وب و PHP

│

└── آموزش PHP

    │

    └── OOP

        │

        ├── Class و Object

        ├── Inheritance

        ├── Interface

        ├── Trait

        ├── Abstract Class

        ├── Dependency Injection ← این مقاله

        ├── SOLID

        └── Design Pattern

نکته مهم برای سئو این مقاله این است که تمرکز اصلی آن روی «تزریق وابستگی و کاهش Coupling» باقی بماند و بحث Container لاراول فقط به عنوان بخش تکمیلی مطرح شود؛ در غیر این صورت ممکن است با مقاله‌های آینده شما درباره Laravel Container و Dependency Injection در Laravel هم‌پوشانی ایجاد شود.

نظرات (0)

نظرات پس از تأیید مدیر نمایش داده می‌شوند

هنوز نظری ثبت نشده است؛ اولین نفر باشید!

مقالات مرتبط

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

ساخت CMS با Laravel 12؛ آموزش ساخت سیستم مدیریت محتوا از صفر

۲۴ دقیقه
ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

ساخت فروشگاه اینترنتی با Laravel 12؛ آموزش پروژه‌محور از صفر تا طراحی هسته فروشگاه

۲۲ دقیقه
ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

ساخت Marketplace با Laravel؛ آموزش طراحی فروشگاه چندفروشندگی

۲۲ دقیقه
مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

مدیریت Queueهای سنگین در Laravel؛ آموزش پردازش کارهای طولانی

۲۲ دقیقه