سال‌ها پیش در یک پروژهٔ فروشگاهی، کدی نوشته بودم که قرار بود مبلغ سفارش را با تخفیف کاربر محاسبه کند. سایت کار می‌کرد، ولی گاهی مبلغ کل اشتباه درمی‌آمد — نه همیشه، فقط در بعضی سفارش‌ها. بعد از چند ساعت، ریشه را پیدا کردم: خطای Undefined variable که در لاگ بود و من ندیده بودمش. متغیر $discount در بعضی مسیرهای کد مقدار نمی‌گرفت و PHP به‌جای هشدار، مقدار null را جایگزین می‌کرد و مبلغ با تخفیف صفر محاسبه می‌شد. آن روز یاد گرفتم Undefined variable در PHP یک هشدار ساده نیست؛ یک علامت قرمز روی منطق برنامه است.

Undefined variable دقیقاً چیست؟

وقتی PHP به متغیری برمی‌خورد که در دامنهٔ فعلی مقدار نگرفته، این خطا را می‌دهد. پیام دقیق چنین است: Warning: Undefined variable $name in /path/to/file.php on line 42. نکتهٔ مهم این‌جاست که این خطا از نوع Warning است، نه Fatal error؛ یعنی کد ادامه پیدا می‌کند، ولی PHP متغیر ناشناخته را در عمل با null جایگزین می‌کند و همین، سرچشمهٔ باگ‌های خاموش است.

PHP به شما نمی‌گوید «کدت خراب است»، می‌گوید «من یک چیزی ندیدم»؛ تفاوت این دو جمله را اگر جدی نگیرید، باگ‌های منطقی به‌سختی پیدا می‌شوند.

چرا این خطا خطرناک است؟

در PHP نسخه‌های قدیمی، Undefined variable فقط یک Notice بود؛ در PHP ۸ به سطح Warning ارتقا پیدا کرد. اما سطح، مهم‌ترین بخش ماجرا نیست. مسئلهٔ اصلی این است که PHP این حالت را «قابل اجرا» می‌داند و با null جلو می‌رود. سه پیامد رایج:

  • خروجی خالی: به‌جای متن یا عدد، هیچ‌چیز نمایش داده نمی‌شود و کاربر فکر می‌کند بخشی از سایت کار نمی‌کند.
  • محاسبهٔ غلط: در عملیات عددی، null معادل صفر می‌شود و نتیجهٔ نهایی بی‌سروصدا غلط درمی‌آید.
  • پیام‌های نمایشی: اگر در سایت زنده خطاها نمایش داده شوند، مسیر فایل‌ها و ساختار کد به کاربر لو می‌رود.

در پست جداگانه‌ای که نوشته‌ام، خطای Notice در PHP را باز کرده‌ام؛ تفاوت این دو از نظر سطح خطا مهم است ولی از نظر اهمیت عملی، هر دو یک چیز را می‌گویند.

تفاوت Undefined variable با Undefined index و Undefined function

این سه معمولاً با هم اشتباه گرفته می‌شوند:

خطامعنینمونه
Undefined variableمتغیر تعریف نشدهecho $name;
Undefined indexکلید آرایه ناموجود$_POST["email"]
Undefined functionتابع فراخوانی‌شده وجود نداردmyCustomFunc();

مورد دوم بسیار رایج است، مخصوصاً وقتی فرم HTML فیلدی را ارسال نمی‌کند ولی کد PHP فرض می‌کند همیشه هست. خطای Undefined function معمولاً به‌دلیل بارگذاری‌نشدن فایل توابع رخ می‌دهد؛ جزئیاتش را در خطای Call to undefined function در PHP نوشته‌ام.

تشخیص: چطور ریشه را در کد پیدا کنیم؟

روش من در پروژه‌ها، چهار گام است:

  1. خواندن پیام با مسیر دقیق: پیام Undefined variable همیشه مسیر فایل و شماره خط را می‌دهد. از همان‌جا شروع کنید.
  2. نگاه به بالادست کد: ببینید چه شرطی باعث شده متغیر مقدار نگیرد. مثلاً یک if که در آن شاخه، متغیر مقدار نمی‌گیرد.
  3. ردیابی مسیر اجرا: با error_log() یا var_dump() مقدار متغیر را در نقاط مختلف کد ببینید تا مطمئن شوید کدام شاخه اجرا می‌شود.
  4. بازتولید در محیط توسعه: همان ورودی را در staging بازتولید کنید تا باگ به‌سادگی دیده شود.
// پیدا کردن مسیر اجرا
error_log("before if: " . ($discount ?? "not-set"));
if ($user->is_vip) {
    $discount = 20;
}
error_log("after if: " . ($discount ?? "not-set"));

این الگو در وردپرس هم کار می‌کند؛ فقط به‌جای error_log می‌توانید از افزونه‌های debug استفاده کنید که لاگ‌ها را در پیشخوان نشان می‌دهند.

راه‌حل‌های امن اصلاح

راه‌حل‌های زیر به ترتیب اولویت توصیه می‌شوند:

  1. مقدار پیش‌فرض بدهید: اگر متغیر واقعاً اختیاری است، از همان ابتدا مقدار بگیرد: $discount = 0;
  2. از عملگرهای null استفاده کنید: $discount = $_POST["discount"] ?? 0; این روش هم خطا را رفع می‌کند هم کوتاه است.
  3. با isset چک کنید: وقتی می‌خواهید منطق متفاوتی برای نبود متغیر اجرا شود، isset() گزینهٔ درست است.
  4. با empty چک کنید: اگر هم نبود و هم خالی بودن متغیر برایتان یکسان است، empty() مناسب‌تر است.

سه روش بالا امن‌اند، ولی هیچ‌کدام جایگزین تشخیص ریشه نیستند. سرکوب کردن خطا با @ اشتباه است.

در وردپرس و افزونه‌ها

در دنیای وردپرس، Undefined variable بیشتر از دو منبع می‌آید:

  • قالب‌های قدیمی: قالبی که برای نسخهٔ قدیمی PHP نوشته شده، حالا روی PHP ۸ خطا می‌دهد. اگر قالب در حال شکستن است، رفع خطای قالب وردپرس مسیر را نشان می‌دهد.
  • افزونه‌های نال: کدی که دست‌کاری شده و متغیرهای لازمش ناقص مانده‌اند. اگر شک دارید، بررسی دانلود افزونهٔ مطمئن ارزشش را دارد.

در صورت انفجار خطاها پس از ارتقای PHP، گاهی سایت حتی به صفحهٔ سفید می‌رسد. در این حالت، راهنمای رفع صفحهٔ سفید وردپرس مسیر نجات است.

اشتباهات رایج

  • سرکوب با @: خطا را پنهان می‌کند ولی منطق غلط سر جای خود باقی است.
  • جاگذاری ?? "" همه‌جا: خروجی خالی به‌جای مقدار درست، همان باگ را می‌سازد با ظاهری آرام‌تر.
  • فرض همیشه‌بودن ورودی فرم: همیشه isset() روی داده‌های کاربر بزنید.
  • بی‌توجهی به خطای Warning: این سطح از خطا در PHP ۸ جدی‌تر از گذشته است و در نسخه‌های بعدی می‌تواند Fatal شود.
هر Undefined variable، یک فرض نانوشته دربارهٔ جریان داده‌ها را افشا می‌کند؛ این فرض‌ها دقیقاً همان‌هایی هستند که در پروژه‌های بزرگ به باگ‌های پرهزینه تبدیل می‌شوند.

درس نهایی

Undefined variable در PHP را می‌توان با یک ?? 0 ساده خفه کرد؛ ولی این کار، باگ را از دید خارج می‌کند نه از کد. تجربه‌ام در پروژه‌های فروشگاهی و فرم‌محور این است: هر وقت این خطا را دیدید، ابتدا بپرسید «چرا این متغیر در این مسیر مقدار نمی‌گیرد؟»، سپس راه‌حل امن را انتخاب کنید. اگر همین یک عادت را در پروژه‌های‌تان جا بیندازید، نصف باگ‌های منطقی‌تان پیش از آن‌که به دست مشتری برسند، خودشان را نشان می‌دهند. اگر شما هم مورد جالبی از این خطا در یک پروژهٔ واقعی دیده‌اید، در دیدگاه‌ها برایم بنویسید. 🔍