Faragiri

همهٔ زبان‌ها

آموزش پایه‌های PHP PHP

آرایه در PHP هم فهرست است و هم نگاشت، و همین ابهام منشا بیشتر باگ‌هاست. یک تابع می‌گوید کدامش را در دست دارید.

۴بخش
۳دقیقه خواندن
۴عمق

یک نوع، دو نقش

ناحیه‌ای که آرایه PHP هر دو کار را در آن می‌کند

وسط این تصویر جایی است که همه ابهام‌ها از آن می‌آیند، چون از بیرون هیچ تفاوتی دیده نمی‌شود.

  • نقش فهرست
  • نقش نگاشت
آرایه با کلیدهای پشت سر هم از صفر
  • نقش فهرستترتیب دارد و در JSON به آرایه تبدیل می‌شود
  • نقش نگاشتکلید دلخواه دارد و در JSON به شی تبدیل می‌شود

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

در PHP فقط یک نوع مجموعه هست و همان یکی هم فهرست است و هم نگاشت. ["hex","square","penny"] یک فهرست است چون کلیدهایش اعداد پشت سر هم از صفرند، و همان ساختار با کلید رشته‌ای یک نگاشت است.

پرسیدنش یک تابع است و نه یک حدس: array_is_list($a) برای فهرست بالا true می‌دهد و برای آرایه‌ای با یک کلید رشته‌ای false. اهمیتش وقتی معلوم می‌شود که خروجی به JSON تبدیل شود: فهرست به آرایه JSON تبدیل می‌شود و نگاشت به شی، و همین یک تفاوت، مصرف‌کننده سمت مرورگر را می‌شکند.

دو تابع دیگر که زیاد لازم می‌شوند و کمتر شناخته‌اند: array_key_first که اولین کلید را می‌دهد بی‌آنکه کل آرایه را پیمایش کنید، و همتای آخرش. پیش از این‌ها، تنها راه بازنشانی اشاره‌گر داخلی آرایه بود.

مقایسه در PHP 8 عوض شده

این تغییر بزرگ‌ترین چیزی است که کد قدیمی را می‌شکند و کد جدید را نجات می‌دهد. با PHP 8، مقایسه یک رشته غیرعددی با یک عدد، عدد را به رشته تبدیل می‌کند و نه برعکس:

  • "abc" == 0 نتیجه false
  • 0 == "" نتیجه false
  • "1e2" == "100" نتیجه true

دو مورد اول در PHP 7 هر دو درست بودند و سال‌ها منشا خطاهای امنیتی در بررسی توکن و رمز بودند. مورد سوم هنوز هست: دو رشته که هر دو عددی باشند به‌شکل عدد مقایسه می‌شوند. برای همین جواب همیشگی همان است: در هر مقایسه‌ای که نتیجه‌اش مهم است، عملگر سه‌نویسه‌ای بنویسید.

آرایه کپی می‌شود و شی نه

انتساب یک آرایه به متغیر دیگر یک کپی می‌سازد: عوض کردن نسخه دوم روی نسخه اول اثر ندارد. انتساب یک شی، همان شی را می‌دهد و عوض کردنش هر دو نام را عوض می‌کند. این تفاوت هیچ‌جا اعلام نمی‌شود و در امضای تابع هم دیده نمی‌شود.

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

جایی که کار گیر می‌کند، کد قدیمی هاست ایرانی است

بخش بزرگی از سایت‌هایی که در ایران نگهداری می‌شوند روی نسخه‌های قدیمی PHP نوشته شده‌اند و روی هاست اشتراکی اجرا می‌شوند. ارتقا به نسخه امروزی معمولا به یک دلیل عقب می‌افتد: کسی نمی‌داند چه چیزی می‌شکند. جواب عملی این است که پیش از هر ارتقایی، کد را زیر ابزار سازگاری اجرا کنید تا فهرست دقیق موارد ناسازگار را بدهد، به‌جای اینکه نسخه را عوض کنید و منتظر بمانید. بیشتر آنچه پیدا می‌شود همان مقایسه‌های سست بالا و توابع حذف‌شده‌اند، و هر دو مکانیکی‌اند.

ابزار، و سالی که این حرف درست است

در سال ۲۰۲۶ نسخه‌ای که یک پروژه باید رویش باشد PHP 8.4 است و نسخه‌های سری ۷ سال‌هاست پشتیبانی امنیتی ندارند. برای دیدن اینکه کد قدیمی با نسخه تازه چه می‌کند، PHPCompatibility روی PHP_CodeSniffer اجرا می‌شود و فهرست موارد ناسازگار را می‌دهد؛ هر دو متن‌باز و رایگان‌اند و از طریق کامپوزر نصب می‌شوند. برای تحلیل ایستا، PHPStan خطاهایی را پیش از اجرا می‌گیرد که این زبان در زمان اجرا هم درباره‌شان ساکت است.

پرسش بعدی این است که وقتی کد از چند فایل بیشتر شد، چطور بدون require دستی بارگذاری شود، که کلاس، فضای نام، و بارگذاری خودکار است. و کتابخانه‌های بیرونی از یک مسیر می‌آیند: وابستگی، نسخه، و پوشه‌ای که بسته‌ها در آن می‌نشینند.

کنار این

بالای این