Reflection یعنی چی

پوریا سبحانلو

پوریا سبحانلو

06 خرداد 1404
دقیقه 6
Reflection یعنی چی
laravel

Reflection یک قابلیته که به برنامه اجازه می‌ده در زمان اجرا (runtime) اطلاعاتی درباره‌ی کد به‌دست بیاره. مثلاً:

لاراول از Reflection استفاده می‌کنه تا امضای متد رو بررسی کنه و هر چیزی که type-hint شده باشه رو از Service Container بگیره. این قابلیت در تمام کنترلرها، رویدادها، دستورها (Commands) و ... کار می‌کنه.

 Reflection یک قابلیته که به برنامه اجازه می‌ده در زمان اجرا (runtime) اطلاعاتی درباره‌ی کد به‌دست بیاره.

 مثلاً:

 

این متد چه پارامترهایی داره؟

 

پارامترها از چه نوعی هستن؟ (type-hint)

چه صفاتی (attributes) روی کلاس یا متد تعریف شده؟

و حتی می‌تونه متد رو صدا بزنه یا خاصیت رو بخونه یا تغییر بده!

✅ چطوری لاراول از Reflection استفاده می‌کنه؟
فرض کن یه کنترلر داری:


class UserController extends Controller
{
   public function sendOtp(Request $request, SmsService $sms)
   {
       // ...
   }
}

 

وقتی کاربر /send-otp رو صدا می‌زنه، لاراول می‌فهمه باید sendOtp رو اجرا کنه. حالا سوال: چطوری؟

لاراول نمی‌دونه SmsService چیه — ولی چون این رو در type-hint می‌بینه، از Reflection استفاده می‌کنه تا امضای متد رو بررسی کنه:


ReflectionMethod::getParameters()

 

می‌گه: خب، این متد دو تا پارامتر داره:

$request از نوع Illuminate\Http\Request

$sms از نوع App\Services\SmsService

لاراول می‌گه: پس من باید از container این دو کلاس رو درست کنم یا از قبل داشته باشم.

حالا Laravel Service Container چی کار می‌کنه؟

$app->make(SmsService::class);

 

این خط، توی Service Container می‌گرده:

آیا SmsService قبلاً singleton شده؟

اگر بله، همونو بده.

اگر نه، باید یک instance بسازه. ولی SmsService ممکنه constructor داشته باشه!

در این لحظه، لاراول دوباره از Reflection استفاده می‌کنه، می‌بینه constructor SmsService چه پارامترهایی داره، مثلاً:


class SmsService
{
   public function __construct(LoggerInterface $logger) { ... }
}

می‌فهمه: برای ساخت SmsService باید اول LoggerInterface رو resolve کنه، و همینطوری ادامه میده تا همه dependency chain درست شه.
در نهایت...
لاراول تمام این مقادیر رو ساخته، و می‌تونه متد sendOtp رو صدا بزنه:

 

$controller->sendOtp($request, $sms);


بدون اینکه تو نیاز باشه دستی چیزی بسازی!

خلاصه
📩 درخواست HTTP میاد

📌 Route متد UserController@sendOtp رو پیدا می‌کنه

🔍 لاراول با Reflection می‌فهمه sendOtp() چه پارامترهایی داره

🧠 از Service Container کمک می‌گیره تا اون پارامترها (مثل SmsService) رو بسازه

🚀 متد رو با پارامترهای آماده اجرا می‌کنه

اگه دوست داشتی با یک مثال real کد ReflectionClass و ReflectionMethod هم نشونت بدم که خودت تو tinker اجرا کنی و ببینی دقیقاً چطوری امضای متد رو می‌خونه. بگی تا بنویسم برات.

بیایم با یه مثال ساده شروع کنیم که با ReflectionClass و ReflectionMethod امضای متد و type-hintها رو بررسی کنیم.

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


// app/Services/SmsService.php
namespace App\Services;
class SmsService
{
   public function send(string $number, string $message)
   {
       // ...
   }
}

 

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


// app/Http/Controllers/UserController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Services\SmsService;
class UserController extends Controller
{
   public function sendOtp(Request $request, SmsService $sms)
   {
       // ...
   }
}

 حالا بیایم داخل Tinker یا هر جای دیگه، با Reflection امضای متد sendOtp رو بررسی کنیم:

 


$reflection = new ReflectionMethod(\App\Http\Controllers\UserController::class, 'sendOtp');
foreach ($reflection->getParameters() as $param) {
   echo "پارامتر: $" . $param->getName() . PHP_EOL;
   $type = $param->getType();
   if ($type && !$type->isBuiltin()) {
       echo " - نوع: " . $type->getName() . PHP_EOL;
   } else {
       echo " - نوع: ساده یا تعریف‌نشده" . PHP_EOL;
   }
}
 

 خروجی:

پارامتر: $request
- نوع: Illuminate\Http\Request

پارامتر: $sms
- نوع: App\Services\SmsService
لاراول دقیقاً همین‌ کارو می‌کنه تا بفهمه چه کلاس‌هایی رو باید resolve کنه.

🔁 اگه کلاس SmsService هم وابستگی داشته باشه چی؟
فرض کن SmsService اینطوری باشه:


class SmsService
{
   public function __construct(\Psr\Log\LoggerInterface $logger) { }
}

بازم لاراول ReflectionClass(SmsService::class)->getConstructor() رو چک می‌کنه و دوباره اون پارامترها رو resolve می‌کنه.


پوریا سبحانلو

پوریا سبحانلو

سلام من پوریام

یه php کاری که ریز نگاهی هم به فریم ورک های js داره


admoon من اینجام

اینارو هم یه نگاه بنداز