
زبان PHP طی سالها توسعه و بهروزرسانی، حالتهای متنوعی برای اجرای کدهای خود ارائه کرده است. از اجرای اسکریپتها توسط خط فرمان گرفته تا تعامل با وبسرورها و حتی اجرای کد در بستر application server ها. هرکدام ویژگیها و محدودیتهای خاص خود را از لحاظ performance، امنیت، scalability و … دارند. درک درست از این حالتهای اجرا، به توسعهدهندگان کمک میکند تا انتخاب درست تری برای محیط اجرای پروژههای خود داشته باشند.
برای درک بهتر این حالتها، آشنایی با چرخهی حیات اجرای کد PHP ضروری است. این چرخه با راهاندازی فرایند اجرا آغاز میشود و از مراحلی نظیر تحلیل واژگانی (lexing)، تجزیهی نحوی (parsing) و تبدیل به کد میانی (opcode) عبور میکند تا در نهایت با استفاده از Zend Engine، خروجی مناسب تولید شود.
در این مقاله، ابتدا اجرای PHP بهوسیلهی CLI و وبسرورها بررسی میشود. سپس به سمت کاربردهای مدرنتر مانند اجرای PHP در بستر application serverها حرکت میکنیم و نمونههایی نظیر FrankenPHP را بررسی خواهیم کرد. در کنار اینها، مفاهیم پایهای مرتبط مثل process و thread نیز برای ایجاد درک کاملتر، به صورت مختصر معرفی خواهند شد. هدف نهایی این مقاله، ارائهی تصویری جامع از مسیرهای مختلف اجرای PHP و انتخاب مناسبترین روش بر اساس نیاز پروژه است.

1. Run php binary
این مرحله آغاز اجرای اسکریپت است. بسته به نوع اجرا (CLI یا Web)، فایل php binary با مسیر فایل php به عنوان ورودی فراخوانی میشود تا پردازش آغاز گردد.
2. Loading Config
در این مرحله فایل پیکربندی php.ini خوانده میشود. تنظیمات مربوط به حافظه، ماژولها، سطح گزارش خطا و سایر تنظیمات اصلی PHP در این فایل قرار دارند که قبل از اجرای کد بارگذاری میشوند.
3. Load Extensions
بر اساس تنظیمات موجود در php.ini، اکستنشنهای مورد نیاز مانند PDO، curl، mbstring و دیگر کتابخانههای بومی یا سفارشی در حافظه بارگذاری میشوند.
اکستنشنها در php بهصورت کتابخانههای داینامیک (Shared Libraries) طراحی شدهاند که در زمان اجرا (Runtime) به برنامه متصل میشوند و مستقیماً در حافظهی همان process اصلی PHP قرار میگیرند. برخلاف اجرای جدا یا ساخت subprocess، این اتصال کاملاً درون process اتفاق میافتد. مکانیزم این اتصال در سطح سیستمعامل معمولاً با استفاده از تابع dlopen انجام میشود، که اجازه میدهد فایلهای .so (در لینوکس) بهصورت داینامیک بارگذاری شوند. این قابلیت انعطافپذیری بالایی ایجاد میکند، چرا که میتوان اکستنشنهایی را بدون نیاز به Recompile کردن PHP، در هر زمان به سیستم اضافه کرد و مورد استفاده قرار داد.
4. Read PHP File from Disk
محتوای فایل PHP مشخصشده از دیسک خوانده شده و به صورت رشته (string) در حافظه ذخیره میشود تا وارد مراحل پردازش زبان شود.
5. Lexing and Parsing
در این مرحله، ابتدا کد به توکنهای معنایی (lexing) تجزیه میشود و سپس این توکنها با قواعد نحوی زبان (parsing) بررسی شده و به یک ساختار درختی نحوی (AST - Abstract Syntax Tree) تبدیل میشوند.
6. Compiling to Opcode
ساختار AST به مجموعهای از دستورالعملهای میانی به نام opcode یا operation code کامپایل میشود. این opcodeها مستقل از معماری CPU هستند و توسط Zend Engine اجرا میشوند.
منظور از «مستقل از معماری CPU» یعنی opcode ها به گونهای تولید میشوند که وابسته به نوع سختافزار یا معماری خاص CPU (مثل x86، ARM یا غیره) نیستند. opcodeها در سطحی عمومی و انتزاعی ایجاد میشوند که میتوانند روی هر پلتفرم یا سیستمی که Zend Engine روی آن اجرا میشود، کار کنند. این ویژگی باعث میشود کد PHP قابل حمل (portable) باشد و بدون نیاز به تغییر یا بازنویسی، روی سیستمهای مختلف اجرا شود، به شرطی که Zend Engine در آن سیستم پشتیبانی شود.
اکستنشن رسمی OPcach که با هدف افزایش کارایی، نتیجهی مرحلهی کامپایل (یعنی opcode) را در RAM ذخیره میکند تا در درخواستهای بعدی نیازی به parse و compile مجدد اسکریپت نباشد. در حالت عادی، PHP هر بار که یک فایل اجرا میشود، باید آن را از دیسک بخواند، تجزیه (parse) کند، به opcode تبدیل کند و سپس اجرا کند. اما با فعال بودن OPcache، این مراحل فقط یکبار انجام میشود و نتیجهی آن در RAM باقی میماند. این یعنی زمان اجرای فایل کاهش مییابد و بار پردازشی سرور نیز کمتر میشود، خصوصاً در اپلیکیشنهایی با درخواستهای زیاد و فایلهای پرتکرار.
7. Run Opcode on Zend Engine
ماشین مجازی Zend Engine، دستورالعملهای opcode را یکی پس از دیگری اجرا کرده و خروجی نهایی را تولید میکند. این مرحله همانجاییست که منطق برنامه واقعاً اجرا میشود.
8. Return to STDOUT
نتیجهی اجرای اسکریپت (مثل HTML یا خروجیهای متنی) به خروجی استاندارد ارسال میشود. در اجرای CLI این خروجی مستقیماً در ترمینال نمایش داده میشود و در حالت وب، به مرورگر کاربر ارسال میشود.
9. Garbage Collector
در پایان، PHP حافظهی اختصاصدادهشده به متغیرهای بدون استفاده را از طریق مکانیزم Garbage Collection آزاد میکند تا منابع سیستم بهینه باقی بمانند.
در سیستمعامل، هر بار که یک برنامه اجرا شود (یک فایل باینری run شود)، یک Process جدید ایجاد میشود. Process بهطور ساده، نمایندهی یک برنامهی در حال اجراست که شامل کد اجرایی، حافظهی اختصاصی، پشته (stack)، دادههای سراسری (heap) و منابعی مثل فایل هاست. سیستمعامل با استفاده از مفهومی بهنام Process میتواند چندین برنامه را همزمان اجرا کند و منابع را بهشکل جداگانه بین آنها مدیریت کند.
در زمینهی PHP، هر بار که فایل باینری PHP اجرا میشود، یک process جدید ساخته میشود. این process مسئول اجرای چرخهی حیات فایل PHP است؛ از خواندن فایل و پیکربندی، تا اجرای opcode و بازگرداندن خروجی. در اجرای خط فرمان (CLI)، هر اجرای دستی شما از دستور php file.php دقیقاً یک process مستقل میسازد.
شناخت مفهوم process به ما کمک میکند تا درک بهتری از اجرای همزمان، مصرف منابع، محدودیتهای حافظه و رفتار برنامه در شرایط مختلف داشته باشیم. همچنین، در حالتهایی که برنامه روی معماریهای مقیاسپذیر اجرا میشود و یا تعداد درخواست ها بالا رود، مدیریت صحیح process ها نقش مهمی در performance و پایداری سیستم ایفا میکند.