چرا تایپهای دقیقتر در PHP زندگی رو راحتتر میکنن؟
خلاصهٔ کاملتر
یه چیزی که برنامهنویسهای حرفهای باهاش دستوپنجه نرم میکنن اینه: باگهایی که از «حالتهای مدیریتنشده» میان. نویسنده این مقاله با یه مثال ساده شروع میکنه — تابعی که به یه حیوان یه صدا نسبت میده — و نشون میده وقتی تایپها شل و گشاد باشن، اضافه کردن یه مقدار جدید (مثلاً ماهی) میتونه بدون هیچ هشداری از آنالایزر استاتیک، کد رو خراب کنه.
مشکل اصلی اینه که وقتی از string ساده برای نمایش مفاهیم محدود (مثل نوع حیوان) استفاده میکنیم، در واقع داریم «magic string» مینویسیم. Magic string یعنی یه رشته که در واقع یه مفهوم غنیتر رو نشون میده، ولی تایپ سیستم ازش خبر نداره. راهحل؟ استفاده از enum بهجای string خام:
enum Animal: string {
case Dog = 'dog';
case Cat = 'cat';
case Fish = 'fish';
}
function noise(Animal $animal): string {
return match($animal) {
Animal::Dog => 'bark',
Animal::Cat => 'meow',
// Match expression does not handle remaining value: Animal::Fish
};
}حالا آنالایزر استاتیک دقیقاً میدونه که Animal::Fish هنوز مدیریت نشده و هشدار میده. در مقابل، وقتی با string کار میکردیم، خطا فقط موقع اجرا و در داخل تابع ظاهر میشد — نه سر جایی که مشکل واقعاً ایجاد شده.
یه نکته مهم دیگه: جایگاه خطاها. با enum، خطا اونجایی گزارش میشه که مقدار اشتباه ساخته شده، نه اونجایی که استفاده شده. این یعنی دیباگ کردن خیلی سریعتر و دقیقتره.
نویسنده بعد وارد بحث امضای توابع میشه. میگه تفاوت مهمی بین «پارامتر ورودی» و «مقدار خروجی» وجود داره: تابع باید بتونه با هر نمونهای از نوع ورودی کار کنه، و کد صداکننده باید بتونه با هر نمونهای از نوع خروجی کار کنه. اگه این قرارداد رعایت نشه، یعنی تایپهامون دروغ میگن.
مثال عملی: یه فرم ثبتنام که دادههای کاربر رو میگیره. اگه اعتبارسنجی داده دیر انجام بشه، ممکنه ایمیل تأییدیه برای کاربر ارسال بشه، بعد تازه بفهمیم که مثلاً نام رو وارد نکرده. با استفاده از DTO (Data Transfer Object)، اعتبارسنجی در همون ابتدا اتفاق میافته:
class UserDto {
public function __construct(
protected string $name,
protected string $email,
) {}
public function toUser(): User {
return new User(
name: $this->name,
email: $this->email,
);
}
}یه نمونه دیگه هم تابع groupByMonth هست که روی آرایهای از آیتمها کار میکنه. اگه تایپ پارامتر فقط array باشه، آنالایزر نمیفهمه که هر آیتم باید کلید month داشته باشه. با PHPDoc دقیقتر، این مشکل قابل تشخیصه:
/**
* @param array<array{month: string, ...}> $items
* @return array<string, array<array{month: string, ...}>>
*/
function groupByMonth(array $items): array { ... }نویسنده تأکید میکنه که تایپ سیگنیچرهای پیچیده، پیچیدگی رو اضافه نمیکنن — فقط پیچیدگیای که قبلاً وجود داشته رو آشکار میکنن. «بهتره با شیطانی که میشناسی طرف بشی.»
در نهایت، ایده اصلی اینه که هرچی تایپها دقیقتر باشن، حالتهای ممکن کمتر میشن، و برنامهنویس کمتر نیاز داره ذهنش رو درگیر «این متغیر الان چیه؟» کنه. این یه سرمایهگذاریه که در طول زمان بازدهی داره.
نکات کلیدی:
- Magic string یعنی رشتهای که مفهومی محدود رو نشون میده ولی تایپ سیستم ازش آگاه نیست — باید با enum جایگزین بشه
- Enum باعث میشه خطاها دقیقاً سر منشأ مشکل گزارش بشن، نه داخل تابع
- امضای تابع یه قرارداده: ورودی باید کاملاً قابل مدیریت باشه، خروجی هم باید کاملاً قابل استفاده
- اعتبارسنجی داده باید هرچه زودتر انجام بشه؛ DTO ابزار خوبیه برای این کار
- تایپهای پیچیده پیچیدگی اضافه نمیکنن، فقط پیچیدگی موجود رو نمایان میکنن
- هرچی تایپها محدودتر و دقیقتر باشن، بار ذهنی خواندن کد کمتره




