سلام دوستان لاراولی! می‌خوایم چهارمین قسمت از مجموعه پست‌های ۸۰ سوال مصاحبه لاراول رو بررسی کنیم. پیشنهاد می‌کنم قبلش مقدمه و قسمت نکته دوستانه رو بخونین 😉

سوالاتی توی این قسمت بررسی می‌کنیم:

  1. Contract های لاراول چیه؟
  2. لاراول از چند نوع درایور Cache پشتیبانی می‌کنه؟
  3. تفاوت Package Manager و Dependency Manager چیه؟
  4. Composer چیه؟
  5. تفاوت {!! !!} و  {{ }} توی Blade چیه؟
  6. چطوری مدل به همراه Migration بسازیم؟
  7. میدل‌ورها کجا می‌تونن استفاده بشن؟
  8. Session کجا ذخیره میشن؟
  9. Eager Loading چیه؟
  10. فرق متد with و load چیه؟

 

31. Contract های لاراول چیه؟

Contract های لاراول چیزی نیستن جز چند تا اینترفیس. همون اینترفیس‌هایی که توی PHP داریم و ازشون استفاده می‌کنیم. به اینترفیس‌هایی که لاراول برای سرویس‌های هسته فریم‌ورک معرفی کرده، میگن Contract.

یک Contract مثل Cache برای این معرفی شده که بتونیم برای سرویس کش، درایورهای مختلفی داشته باشیم. همین‌طور برای سرویس‌هایی مثل Mail و Cookie. این Contract ها شامل چند متد انتزاعی هستن برای همه درایورهایی که می‌خوان این سرویس‌ها رو پیاده‌سازی کنن.

برای دونستن فواید استفاده از Contract ها، باید فواید اینترفیس‌ها رو بدونیم. یکی از فواید استفاده از اینترفیس‌ها Loose Coupling هست. کد زیر و متد build رو در نظر بگیرید که بدون استفاده از اینترفیس‌ها نوشته شده:

<?php

class Repository
{
    public function build(SomePackage\Cache\Memcached $cache)
    {

    }
}

نوشتن برنامه به چنین سبکی، توسعه رو سخت می‌کنه. کلاس و متد ما وابستگی زیادی به کلاس Memcached داره و برای استفاده کردن از یک درایور دیگه باید کلاس و متد رو دستکاری کنیم. بهترین کار برای حل این مسئله، استفاده از اینترفیس‌ها هست. توی متد، از Contract (اینترفیس) Cache استفاده می‌کنیم:

<?php

use Illuminate\Contracts\Cache\Repository as Cache;

class Repository
{
    public function build(Cache $cache)
    {

    }
}

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

تفاوت اینترفیس و کلاس Abstract
اصول SOLID به زبان ساده - اصل دوم

 

32. لاراول از چند نوع درایور Cache پشتیبانی می‌کنه؟

بی‌نهایت! این سوال ارتباط زیادی به سوال بالا داره. اگه برای یک سرویس خاص، Contract یا اینترفیس اون موجود باشه، می‌تونیم بی‌نهایت درایور بسازیم و استفاده کنیم. برای مثال برای ساختن یک درایور شخصی برای کش، کافیه از Contract مربوط به Cache تبعیت کنیم:

<?php

namespace App\Extensions;

use Illuminate\Contracts\Cache\Store;

class MongoStore implements Store
{
    public function get($key) {}
    public function many(array $keys) {}
    public function put($key, $value, $seconds) {}
    public function putMany(array $values, $seconds) {}
    public function increment($key, $value = 1) {}
    public function decrement($key, $value = 1) {}
    public function forever($key, $value) {}
    public function forget($key) {}
    public function flush() {}
    public function getPrefix() {}
}

 

33. تفاوت Package Manager و Dependency Manager چیه؟

قبل از بررسی تفاوت‌ها بهتره با یک مقدمه آشنا بشیم. نرم‌افزارهای مدرن و بزرگ همگی از اجزای کوچیک و مستقل تشکیل میشن. یک نرم‌افزار برای توسعه، نیاز به نرم‌افزارها و کتابخونه‌های خارجی داره و برای فعالیت کردن، به نوعی وابسته به ابزاری هست که توسط بقیه نوشته شده. پس برای اجرای کامل یک نرم‌افزار نیاز به جمع‌آوری همه وابستگی‌ها داریم. یک راه سخت اینه که همه این وابستگی‌ها رو خودمون فراهم و نصب کنیم. شرایط زمانی سخت‌تر میشه که یک ابزار وابسته به یک ابزار دیگه باشه. همین مسئله سبب شد تا ابزار‌هایی مثل Dependency Manager و Package Manager معرفی بشن. این ابزارها مسئول فراهم و مدیریت کردن ابزارهایی هستن که ما برای توسعه نرم‌افزار نیاز داریم. حالا به بررسی تفاوت‌ها می‌پردازیم.

Dependency Manager فقط در سطح نرم‌افزار فعالیت می‌کنه. یعنی وابستگی‌های یک برنامه که توسط Dependency Manager نصب میشه، فقط در سطح همون برنامه قابل دسترسی هست.

Package Manager در سطح بالاتر و کلی‌تر فعالیت می‌کنه. یعنی در سطح سیستم و نه برای یک برنامه خاص. ابزارهایی که توسط Package Manager نصب میشه، می‌تونه برای چندین برنامه استفاده بشه و تاثیرگذار باشه.

مثلاً برای توسعه برنامه‌های لاراولی اگه به پکیج image/intervention نیاز داریم، باید برای هر پروژه این پکیج رو جدا و با کامپوزر نصب کنیم. پس کامپوزر یک Dependency Manager هست.

 

34. Composer چیه؟

کامپوزر یک ابزار مدیریت وابستگی (Dependency Management) برای PHP هست که به ما اجازه میده تا ابزارهای مورد نیاز برنامه‌مون رو نصب و مدیریت کنیم.

هر چند کامپوزر با پکیج‌ها سر و کار داره، ولی Package Manager به حساب نمیاد. چون پکیج‌ها رو فقط در سطح پروژه مدیریت می‌کنه.

 

35. تفاوت {!! !!} و  {{ }} توی Blade چیه؟

هر دو برای نمایش اطلاعات به کار میرن. {{ }} برای جلوگیری از حمله XSS بکار میره. وقتی از اون برای نمایش اطلاعات استفاده می‌کنیم، اطلاعات ابتدا از تابع htmlspecialchars عبور می‌کنه و بعد نمایش داده میشه.

{{ "<script>alert('Hello')</script>" }}

خروجی کد بالا بصورت زیر هست:

&lt;script&gt;alert(&#039;Hello&#039;)&lt;/script&gt;

اما اگه بجای {{ }} از {!! !!} استفاده کنیم، اطلاعات خام و بدون تبدیل نمایش داده میشن:

{!! "<script>alert('Hello')</script>" !!}

با اجرا شدن کد بالا، محتویات درون تگ script اجرا میشه و اینجا یک alert جاوااسکریپتی می‌گیریم. پس باید در نظر داشته باشیم زمانی که می‌خوایم اطلاعاتی رو نمایش بدیم که از صحت اون اطمینان نداریم، مثلاً فرمی که یک کاربر ثبت کرده، بهتره که از {{ }} استفاده کنیم.

 

36. چطوری مدل به همراه Migration بسازیم؟

وقتی می‌خوایم با دستور آرتیزان یک مدل بسازیم، به طوری که همزمان و به طور خودکار فایل مایگریشن اون هم ساخته بشه، کافیه گزینه --migration یا -m رو توی دستور آرتیزان مشخص کنیم:

php artisan make:model Book --migration

php artisan make:model Book -m

با دستور بالا ابتدا مدل و بعد یک مایگریشن به اسم (حالت جمع) همون مدل ساخته میشه تا با این کار با یک تیر دو نشون زده باشیم 😉

 

37. میدل‌ورها چند حالت می‌تونن استفاده بشن؟

توی لاراول میدل‌ورها می‌تونن ۳ حالت استفاده بشن.

میدل‌ور سراسری

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

میدل‌ور روت‌ها

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

میدل‌ور کنترلرها

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

class UserController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');

        $this->middleware('log')->only('index');

        $this->middleware('subscribed')->except('store');
    }
}

برای اطلاعات بیشتر از میدل‌ورها و کنترلرهای لاراول می‌تونین پست‌های زیر رو بخونین:

 

38. Session کجا ذخیره میشن؟

درایور پیشفرض لاراول برای نگهداری سشن‌ها file هست. یعنی سشن‌ها بصورت فایل و توی مسیر /storage/framework/sessions ذخیره میشن. اگه یکی از فایل‌های سشن رو باز کنیم، می‌بینیم که اطلاعات سشن بصورت serialize شده ذخیره شدن.

لاراول این امکان رو میده تا بتونیم برای سشن‌ها درایورهای مختلفی داشته باشیم. علاوه بر file، فریم‌ورک درایورهایی مثل cookie - database - memcached - redis و آرایه PHP رو در اختیار قرار گذاشته.

 

39. Eager Loading چیه؟

این تکنیک برای حل کردن مشکل N + 1 ساخته شده. فرض کنیم توی مدل کاربر، یک رابطه داریم به اسم book. حالا کد زیر رو در نظر بگیرید:

$users = User::all();

foreach ($users as $user) {
    echo $user->book->name;
}

اگه کوئری خط اول، N کاربر رو برگردونه، خط چهارم باعث به وجود اومدن مشکل N + 1 میشه. یعنی برای لود کردن کتاب‌های هر کاربر، یک کوئری جدا و اختصاصی زده میشه:

select * from books where user_id = 1
select * from books where user_id = 2
select * from books where user_id = 3
select * from books where user_id = 4
...

با Eager Loading می‌تونیم به جای N + 1 کوئری، فقط ۲ تا کوئری داشته باشیم. یک کوئری برای خوندن کاربرها و یک کوئری برای خوندن کتابشون:

select * from users
...
select * from books where user_id in (1, 2, 3, 4)

این تکنیک توسط متدهای with و load توی لاراول قابل اجرا هست:

$users = User::all()->load('book');

foreach ($users as $user) {
    echo $user->book->name;
}

 

40. فرق متد with و load چیه؟

هر دو متد برای پیاده‌سازی تکنیک Eager Loading معرفی شدن. وقتی از متد with استفاده می‌کنیم، کوئری دوم بلافاصله بعد از کوئری اول زده میشه. یعنی اینجا بطور حتم (حداقل) دو تا کوئری داریم:

$users = User::with('book')->get();

اما از متد load که به اون Lazy Eager Loading هم گفته میشه، برای زمانی استفاده می‌کنیم که می‌خوایم کوئری دوم رو زمان و جایی اجرا کنیم که دلمون می‌خواد:

$users = User::all();

// Somewhere in the app
if ($condition) {
    $users->load('books');
}

 

خب دوستان امیدوارم از این قسمت استفاده کرده باشین. روزتون خوش. 😉✌️

برای این قسمت از منابع زیر کمک گرفتم: