درک کانتینر سرویس لاراول

ترجمه و تالیف : علی اسماعیلی
تاریخ انتشار : 13 خرداد 98
خواندن در 3 دقیقه
دسته بندی ها : لاراول

یادگیری نحوه ساختن یک برنامه با لاراول صرفا یادگیری استفاده از کلاس‌ها و اجزای مختلف در خود فریمورک، یادآوری تمام دستورات artisan و یا تمامی توابع کمکی نیست.

درک کانتینر سرویس لاراول

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

بخش عمده‌ای از فلسفه لاراول را Service Container یا IoC در برمی‌گیرد.

به عنوان یک توسعه دهنده لاراول، شناخت و استفاده درست ازService Container  بخش مهمی در مدیریت مهارت شما است، زیرا هسته هر برنامه لاراول است.

اصول اولیه

اساسا IoC Container فقط یه کلاس ساده PHP است، اما من دوست دارم از آن به عنوان (کیسه‌ای از تکنیک‌ها و ترفند‌ها) نام ببرم.

این کیسه جایی است که ما می خواهیم اتصالات همه چیزهایی که در برنامه لاراول نیاز داریم را هموار کنیم، از پیاده سازی interfaces تا مسیرهای راهنما و… .

در حال حاضر، از آنجایی که ما تنها یک شئ داریم که شامل کلیدهای مختلف است بسیار آسان است که آنها را در هر نقطه از کد بازیابی کنیم یا آنها را حل کنیم.

Binding and Resolution

اکنون تصور کنید که یک Class FooService خاص داریم که خدمات خاصی را ارائه می دهد.

namespace App\Services;
class FooService
{
    public function __construct()
    {
        ...
    }
    public function doSomething()
    {
        // Code for Something.
    }
}

اگر ما می‌خواستیم از کلاس و متد doSomething استفاده کنیم، می توانیم کاری شبیه به این را انجام دهیم:

$fooService = new \App\Services\FooService();
$fooService->doSomething();

این فوق العاده است، اما چیزی که در اینجا من را به خنده می‌آورد کلید واژه new است. منظورم این نیست که دارم کار اشتباهی را انجام میدهم این عالیست، اما شاید ما در اینجا می‌توانیم بهتر عمل کنیم.

چگونه Bind کنیم

میتوان با کد زیر عملیات bind کردن را به سادگی انجام داد:

$this->app->bind('FooService', \App\Services\FooService::class);

اساسا ما به لاراول می گویم: "سلام این شی را در bag of tricks ذخیره کن و آن را به عنوان FooService برچسب گذاری کن".

البته راه های دیگری برای اتصال سرویس‌ها به بسته‌های وضعیت و نحوه استفاده از سرویس‌ها وجود دارد، اما شما ایده اولیه را دریافت می‌کنید.

چگونه حل می‌کنیم

بعد از اینکه سرویس‌های ما در container قرار گرفت، اکنون می‌توانیم آن را از هر نقطه از برنامه بازیابی یا حل کنیم.

// Using IoC we could end up with this
$fooService = app()->make('FooService');
$fooService->doSomething();
// Eventually this, basically one line of code
app()->make('FooService')->doSomething();

در اینجا ما فقط به لاراول می‌گوییم: "به یاد داشته باش که FooService من رو به خوبی نگه‌دار و هر وقتی بهش نیاز داشتم، پس فقط به من پس‌ش بده".

آیا متوجه شدید که با استفاده از IoC برای ایجاد سرویس، کدهای‌تان بسیار تمیز، ظریف و خواندنی‌تر (readability) می‌شوند.

این زیبایی لاروال است و به عنوان یک پاداش اضافه شده، کد شما اکنون راحت‌تر استفاده می‌شود، زیرا شما اکنون می توانید FooService را با یک شیء فریبنده جایگزین کنید.

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

رابط اتصال با IoC

یک رابط در برنامه‌ریزی شئ‌گرا یک راه برای ایجاد کلاس‌هایی است که باید به نوعی از طرح یا قرارداد پیروی کنند.

این به دیگر توسعه‌دهندگان کمک می‌کند که با شما کار کنند و شما بتوانید کدی ایجاد کنید که با محدودیت های موجود در رابط کاربری شما مطابقت داشته باشد.

این کار، آنها را برای بازگشت به یک نوع داده خاص و انتقال مجموعه ای از پارامترهای ثابت به روش های خود هدایت می‌کند، خواه اگر روش‌های متفاوتی را نیز در پیش بگیرند.

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

با استفاده از IoC Laravel می توانیم پیاده سازی خاصی از یک رابط را به آن متصل کنیم، به این ترتیب وقتی که ما این رابط را طراحی می‌کنیم، با کلاس اصلی کار اتصال را انجام می‌دهیم.

$this->app->bind(FooInterface::class, FooClass::class);

از این رو، هنگامی که FooInterface حل شده است، لاراول  به اندازه کافی هوشمند است تا نمونه ای از FooClass را به ما بدهد.

در حال حاضر تصور کنید ما یک اجرای بهتر FooInterface به نام BarClass را نوشته‌ایم و می‌خواهیم از آن برای FooClass استفاده کنیم. بنابراین نیاز به تغییر داریم:

$this->app->bind(FooInterface::class, FooClass::class);

کد ما همچنان همان کار را انجام می‌دهد، زیرا می‌دانیم که BarClass با interface     رابطه دارد و اگر BarClass تا به حال اجرا نشده باشد می تواند آن را به FooClass تغییر دهد. این یک راه عالی برای ارتقاء یک برنامه کاربردی بدون regressions‌های زیاد است.

حل کردن مشکل وابستگی‌ها

ما می دانیم که Laravel می‌تواند یک سرویس یا interface را که به IoC متعهد است، حل کند، اما می تواند خیلی بیشتر از آن را نیز انجام دهد.

در واقع می‌توان وابستگی‌های این سرویس‌ها را برای ما بدون نیاز به نوشتن یک خط از کد حل کند.

تصور کنید کلاس های زیر را در برنامه داریم:

// BarService.php

class BarService
{
  /**
   * Something to do.
   *
   * @return string
   */
  public function somethingToDo()
  {
    return 'I am doing something';
  }
}

// FooService.php

class FooService
{
  /**
   * The BarService instance.
   *
   * @var BarService
   */
  protected $bar;
  
  /**
   * Create new instance of FooService.
   *
   * @param BarService $bar
   */
  public function __construct(BarService $bar)
  {
    $this->bar = $bar;
  }
  
  /**
   * Do something useful.
   *
   * @return string
   */
  public function doSomething()
  {
    return $this->bar->somethingToDo();
  }
}

همانطور که می‌بینیم، FooService به نمونه‌ای از BarService نیاز دارد تا قادر به نمونه‌برداری باشد. چطور می‌توانیم این را در ظرفی متصل کنیم به طوری که هر زمان که لاراول نمونه ای از FooService را به ما نشان دهد و نمونه‌ای از BarService را نیز به ما بدهد؟

خوب، شما ممکن است فکر کنید راه حل این است که این کار را انجام دهید:

$this->app->bind('Foo', new FooService(new BarService));

از لحاظ فنی که کار می‌کند، اما واقعا لازم نیست. Laravel به طور خودکار آن را برای ما با استفاده از یک ویژگی قدرتمند از پی اچ پی که «بازتاب» نامیده می شود انجام می‌دهد، از این رو شما به طور معمول به خودتان ملحق می‌شوید:

$this->app->bind('Foo', FooService::class);

حالا وقتی Foo را حل می‌کنیم، پشت صحنه لاراول به FooService نگاه می‌کند، می‌بیند که به یک نمونه از BarService نیاز دارد؛ از این رو لاراول BarService را تهیه کرده و آن را به سازنده FooService عرضه می‌کند و به ما نمونه کاملا ساخته شده بدون نیاز به نوشتن یک خط کد را می‌دهد.

علاوه بر این، این فرآیند برای همه وابستگی‌ها خود را تکرار خواهد کرد، بنابراین اگر BarService ‌وابستگی داشته باشد، این نیز حل خواهد شد.

کلام آخر

چیزهای زیادی برای بحث و بررسی در مورد IoC در لاراول وجود دارد. من امیدوارم که این مقدمه کمی سبب روشن شدن قضیه شده باشد و به شما کمک کند تا اطلاعاتی در مورد container پیدا کنید.

منبع 

نویسنده مهمان : علی اسماعیلی

دیدگاه‌ها و پرسش‌ها

برای ارسال نظر لازم است ابتدا وارد سایت شوید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید