ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

一个 `.php` 文件从你敲下命令到屏幕上输出结果,中间经历了哪些步骤?

一个 `.php` 文件从你敲下命令到屏幕上输出结果,中间经历了哪些步骤? 场景命令行执行php test.phpCLI模式不是网页访问区分FPM前提系统环境已经安装PHP解释器并且把php可执行文件加入环境变量PATH根因PHP本身是解释型语言不是直接CPU执行。敲下php命令后操作系统、PHP内核、Zend引擎依次完成找到程序、读取源码、词法语法分析、编译成中间字节码、Zend虚拟机执行字节码最终输出字符到终端屏幕。完整分步拆解步骤1Shell接收你输入的命令php test.php你在终端敲回车shellbash/zsh/cmd读取整行字符串。Shell拆分命令程序名php参数test.php在系统PATH环境变量目录中搜索找到php这个可执行二进制程序php-cli操作系统调用系统调用fork创建新进程exec加载php-cli程序启动PHP进程。步骤2PHP内核启动接收参数定位目标php文件PHP进程启动初始化内核、加载php.ini配置加载扩展mysqli、json等、设置内存上限、错误等级。读取传入参数test.php判断文件名是否存在、是否可读文件不存在直接抛出No such file or directory报错。打开文件通过操作系统read系统调用把test.php源码文本读取到内存。源码此时仍然是纯文本字符串?php ... ?。步骤3词法分析Lex 词法扫描Zend引擎的词法分析器扫描源码字符流。把连续文本切割成Token标记关键字if、echo、变量$a、数字、字符串、分号、括号。简单理解把文章切成一个个词语剔除空格、注释。遇到语法字符错误这一步就报词法错误。步骤4语法分析Yacc 语法解析拿到Token流按照PHP语法规则构建抽象语法树 AST。AST是树形结构代表代码逻辑哪一段是表达式、哪一段是分支、哪一段是函数调用。这一步会检查语法少写分号、括号不匹配在这里抛出语法解析错误。步骤5编译AST → Zend 字节码opcodeZend引擎遍历AST翻译成Opcode操作码。Opcode是Zend虚拟机能识别的指令类似Java的bytecode不是机器码不能直接交给CPU运行。开启opcache之后会把编译好的Opcode缓存下次执行直接跳过词法语法编译直接拿缓存字节码提升速度。本次第一次执行无缓存。步骤6Zend虚拟机执行OpcodeZend VM逐条解释执行Opcode开辟内存创建变量、数组、对象运算、函数调用遇到echo这类输出指令不会直接写屏幕先交给PHP内核输出缓冲区output buffer代码过程中执行IO操作读文件、数据库连接会发起对应的操作系统系统调用。步骤7输出缓冲区刷新操作系统输出到终端echo输出内容先写入PHP输出缓冲区。脚本执行结束自动刷新buffer。PHP调用操作系统write系统调用把文本数据写入标准输出stdout。操作系统内核把stdout的数据交给终端程序终端渲染字符在显示器屏幕展示文字结果。步骤8脚本执行完毕资源回收进程退出释放变量内存关闭打开的文件、数据库连接PHP做垃圾回收GC回收无引用对象PHP进程退出操作系统回收进程占用内存、文件描述符等资源。【区分补充】如果是浏览器访问 http://xxx/test.phpFPM模式和CLI不一样浏览器发起HTTP请求 → Nginx/Apache接收请求Web服务器识别后缀.php转发请求给PHP-FPMFPM子进程接收请求读取php源码同样走词法→语法→AST→Opcode→Zend VM执行echo输出内容组装成HTTP响应报文回传给Nginx再返回浏览器浏览器渲染页面。误区澄清误区1PHP源码直接翻译成CPU机器码执行。纠正PHP是Zend虚拟机解释Opcode不是直接编译成机器码。只有HHVM这类JIT模式才会把Opcode动态编译成机器码。误区2echo直接写屏幕。纠正echo写入PHP输出缓冲区脚本结束才一次性输出减少系统调用次数。一句话总结Shell找到php-cli程序创建进程PHP读取php源码经过词法切Token、语法生成AST编译成Zend字节码虚拟机执行指令输出内容写入缓冲区刷新后通过系统调用输出到终端执行结束释放资源进程退出。
返回列表