Faragiri

همهٔ زبان‌ها

آموزش سازه‌های اصلی برنامهمبانی برنامه‌نویسی · متغیر و نوع داده، ساختارهای کنترلی، تابع و ۱ مورد دیگر

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

۴شاخه
۴زیرمجموعه
۳عمق

پنج تا

چه چیزی یک برنامه را سرپا نگه داشته است

هرکدام از این ستون‌ها را بردارید، برنامه‌ای نمی‌ماند، فقط یک سند می‌ماند.

هر برنامه‌ای همین پنج تاست، چیده‌شده
  • نامی برای یک مقدارnerkh_barg = 1200
  • یک انتخابکاغذ گلاسه نرخ دیگری دارد
  • یک تکراریک بار برای هر سفارشی که روی میز است
  • یک فراخوانیhazine(tedad)، یک بار نوشته و هر سفارش یک بار صدا زده
  • یک شکست عمدیسفارشی که تعداد ندارد، به‌جای حدس زده شدن متوقف می‌شود

کتابخانه و کلاس و ماژول و نوع، راحتی‌هایی هستند که روی همین پنج تا ساخته شده‌اند. هیچ‌کدام ستون ششم نیستند.

ستون‌ها هم‌ترازند و ترتیبشان دلبخواهی است. برنامه‌ای که فقط نام می‌بندد و هیچ‌وقت انتخاب نمی‌کند، فهرستی از مقدارهاست، یعنی یک فایل و نه یک برنامه.

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

  • nerkh_barg = 1200 یک نام را به یک مقدار می‌بندد
  • if noe == "glasse": nerkh_barg = 2500 انتخاب می‌کند
  • for tedad in sefareshha: روی سفارش‌های روی میز تکرار می‌کند
  • def hazine(tedad): return max(tedad * nerkh_barg, 50000) تکه‌ای از کار را نام می‌گذارد و جواب پس می‌دهد
  • raise ValueError("سفارش بدون تعداد") عمداً متوقف می‌شود

یک نام، یک انتخاب، یک تکرار، یک فراخوانی و یک شکست عمدی. هر برنامه‌ای که تا امروز خوانده‌اید همین پنج تاست، چیده‌شده. سفارش ۸۰ برگی گلاسه ۹۶ هزار تومان درمی‌آید و سفارش ۴ برگی همان کف هزینه، ۵۰ هزار تومان.

همان پنج تا، با املای دیگر

در PHP هر نام یک دلار جلو دارد، بلوک را آکولاد نگه می‌دارد به‌جای تورفتگی، و foreach ($sefareshha as $tedad) همان کاری را می‌کند که for tedad in sefareshha. همین. برای همین است که زبان دوم دو هفته وقت می‌گیرد و نه یک سال، و تمام آن دو هفته باید صرف چند جایی شود که املا فرق نمی‌کند و معنا فرق می‌کند.

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

تابع در PHP نامِ بیرون خودش را نمی‌بیند

این ترجمه سطر به سطر همان برنامه است و هر سطرش درست به نظر می‌رسد:

  • $nerkh_barg = 1200;
  • function hazine($tedad) {
  • return max($tedad * $nerkh_barg, 50000);
  • }

در پایتون این کار می‌کند، چون نام تعریف‌شده بیرون تابع در پایتون خوانده می‌شود و در PHP نه. در PHP تابع فقط آرگومان‌های خودش را دارد و $nerkh_barg داخلش یک نام تازه و خالی است. PHP برای متغیر ناشناخته هشدار می‌دهد و برنامه با مقدار صفر ادامه می‌دهد، پس ضرب صفر می‌شود، کف هزینه برنده می‌شود، و هر سفارش، از چهار برگ تا هشت هزار برگ، ۵۰ هزار تومان فاکتور می‌خورد. هیچ سطری قرمز نمی‌شود. روی سرور، آن هشدار معمولاً در لاگی می‌نشیند که کسی باز نمی‌کند.

راه درستش یک کلمه است: global $nerkh_barg; نام بیرونی را به داخل تابع می‌آورد و هر دو زبان همان دو عدد را می‌دهند. راه بهترش این است که نرخ را آرگومان کنید و اصلاً به بیرون تکیه نکنید، که همان چیزی است که یک مقدار چیست و چه کارهایی رویش مجاز است از سمت دیگر می‌گوید.

دو مقایسه که در دو زبان یک جواب ندارند

ستون تعداد گاهی خالی است، چون اپراتور فرم را نیمه‌کاره رها کرده. (int)"" در PHP صفر است و int("") در پایتون ValueError می‌دهد. یعنی همان سفارش در یک زبان برنامه را متوقف می‌کند تا کسی نگاهش کند، و در زبان دیگر می‌شود سفارشی با صفر برگ که باز هم کف هزینه می‌گیرد و در جمع روز گم می‌شود. کدام‌یک را می‌خواهید تصمیم شماست؛ ندانستن اینکه کدام را دارید تصمیم شما نیست. این خانواده کامل خطاها موضوع شکستن با صدا، شکستن بی‌خطر، و فرق این دو است.

دومی به مقایسه برمی‌گردد. "3" == 3 در PHP درست است و در پایتون نادرست، چون PHP دو طرف را به هم نزدیک می‌کند و پایتون نمی‌کند. تا پیش از PHP 8 این نزدیک کردن تا جای عجیبی می‌رفت و "abc" == 0 هم درست بود؛ از PHP 8 در سال ۲۰۲۰ مقایسه رشته و عدد از سمت رشته انجام می‌شود و آن یکی نادرست شد. یک جا هم هست که دو زبان با هم موافق‌اند و کمتر کسی انتظارش را دارد: آرایه خالی در هر دو زبان نادرست است، پس if ($sefareshha) و if sefareshha: اینجا یک معنا دارند. جایی که شرط‌ها و حلقه‌ها از خوانا بودن درمی‌آیند شاخه‌ها و حلقه‌ها، و خوانا نگه داشتنشان است.

همان پنج تا

چاپخانه اصفهان، دو بار نوشته‌شده

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

پایتونتورفتگی بلوک را نگه می‌دارد
PHPآکولاد بلوک را نگه می‌دارد و هر نام یک دلار جلو دارد
بستن یک نامnerkh_barg = 1200$nerkh_barg = 1200;
انتخابif noe == "glasse":if ($noe === "glasse") {
تکرار روی مقدارهاfor tedad in sefareshha:foreach ($sefareshha as $tedad) {
برگرداندن هیچNoneNULL
شکستن عمدیraise ValueError(...)throw new InvalidArgumentException(...)

سطری که در این جدول جا نمی‌شود همان است که اهمیت دارد: تابع در پایتون نامِ بیرون خودش را می‌بیند و در PHP نمی‌بیند، و هیچ املایی این را جبران نمی‌کند.

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

Ruff در سال ۲۰۲۶ پیش‌فرض پایتون است، هم قالب‌بند و هم بازرس، و جای flake8 و isort و black را گرفت که سه بار جدا روی یک فایل راه می‌رفتند. رایگان و متن‌باز است. PHPStan همین کار را از سمت معنا برای PHP می‌کند: فایل را بدون اجرا می‌خواند و نامی را که تابع استفاده می‌کند و هرگز نگرفته است گزارش می‌دهد، یعنی دقیقاً همان اشتباه دو بخش بالاتر را پیش از رسیدن به سرور می‌گیرد. هسته‌اش متن‌باز است. نسخه جاری خود PHP در سال ۲۰۲۶ نسخه 8.5 است و جانشین 8.4 شد.

هیچ‌کدام از این سه درباره تله معنایی بالا نظری ندارند وقتی کد بدون نام گمشده نوشته شده باشد. یک قالب‌بند املای پنج سازه را بررسی می‌کند و هرگز معنایشان را.

اشتباه: پنج سازه را پنج تکه نحو یاد گرفتن

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

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

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

درون این، ۴

کنار این

بالای این