PHP如何执行 - 从源代码到渲染
本文由Younes Rafie进行了同行评审。感谢SitePoint所有的同行评审员制作SitePoint内容的最佳状态!
>受Ruby代码如何执行的最新文章的启发,本文涵盖了PHP代码的执行过程。
钥匙要点
PHP代码的执行涉及四个阶段:Lexing,解析,编译和解释。每个阶段在将PHP源代码转换为机器可读代码的过程中至关重要。
> Lexing或令牌化是将字符串(PHP源代码)变成一个令牌序列的过程。每个令牌是其匹配值的命名标识符。此阶段还存储lexeme和匹配令牌的行号。- 验证令牌顺序的有效性,并生成抽象语法树(AST)。 AST是在编译阶段使用的源代码的树视图。
- 解释阶段是在Zend Engine(ZE)VM上运行Opcodes的最后阶段。此阶段的输出是您的PHP脚本通过echo,print,var_dump等命令输出的内容。 >
- 简介
- >当我们执行PHP代码时,引擎盖下发生了很多事情。从广义上讲,执行代码时,PHP解释器将经历四个阶段:
- Lexing
- 解析
汇编
解释
- >本文将浏览这些阶段,并展示我们如何查看每个阶段的输出,以真正查看发生了什么。请注意,虽然某些使用的扩展程序应该已经是您的PHP安装的一部分(例如Tokenizer和opcache),但需要手动安装和启用其他扩展程序(例如,PHP-ast和VLD)。 阶段1 - Lexing
- Lexing(或令牌化)是将字符串(在这种情况下为PHP源代码)转换为令牌序列的过程。令牌只是其匹配的值的命名标识符。 PHP使用re2c从zend_language_scanner.l定义文件。 >我们可以通过令牌扩展名看到Lexing阶段的输出:
- >输出:
$code = <<<'code' <span><span><?php </span></span><span><span>$a = 1; </span></span><span>code<span>; </span></span><span> </span><span><span>$tokens = token_get_all($code); </span></span><span> </span><span><span>foreach ($tokens as $token) { </span></span><span> <span>if (is_array($token)) { </span></span><span> <span>echo "Line <span><span>{$token[2]}</span>: "</span>, token_name($token[0]), " ('<span><span>{$token[1]}</span>')"</span>, PHP_EOL; </span></span><span> <span>} else { </span></span><span> <span>var_dump($token); </span></span><span> <span>} </span></span><span><span>} </span></span>
>从上述输出中有几个值得注意的点。第一个点是,并非所有源代码的所有部分都命名为令牌。相反,某些符号本身被视为令牌(例如=,;,:,?等)。第二点是,Lexer实际上做的不只是简单地输出一个令牌流。在大多数情况下,它也存储了lexeme(由令牌匹配的值)和匹配令牌的行号(用于堆栈跟踪之类的内容)。
阶段2 - 解析也生成了解析器,这次是通过BNF语法文件与野牛一起生成的。 PHP使用LALR(1)(向前,从左到右)无上下文语法。前面的外观仅意味着解析器能够在解析时可能会遇到的歧义。从左到右的部分意味着它从左到右解析令牌流。
>>生成的解析器阶段将令牌流从Lexer作为输入中获取,并有两个作业。首先,它通过尝试将其与BNF语法文件中定义的任何语法规则相匹配,从而验证令牌顺序的有效性。这样可以确保令牌流中的代币形成有效的语言构造。解析器的第二个作业是生成
抽象语法树(AST) - 下一阶段将使用的源代码的树视图(汇编)。
我们可以使用php-ast扩展名来查看
Line 1: T_OPEN_TAG ('<?php ') Line 2: T_VARIABLE ('$a') Line 2: T_WHITESPACE (' ') string(1) "=" Line 2: T_WHITESPACE (' ') Line 2: T_LNUMBER ('1') string(1) ";"
$code = <<<'code' <span><span><?php </span></span><span><span>$a = 1; </span></span><span>code<span>; </span></span><span> </span><span><span>print_r(ast<span>\parse_code</span>($code, 30)); </span></span>
>标志 - 一个指定过载行为的整数(例如,ASTAST_BINARD_OP节点将具有区分发生哪些二进制操作的标志)
Lineno- lineno - 线号,从较早的令牌信息中可以看出
- 儿童 - 子节点,通常会进一步分解该节点的一部分(例如,功能节点将具有孩子:参数,返回类型,身体等)
- >此阶段的AST输出很方便用于诸如静态代码分析仪(例如phan)之类的工具。
阶段3 - 汇编
汇编阶段消耗了AST,它通过递归穿越树来发出opcods。这个阶段还进行了一些优化。这些包括通过字面论据(例如strlen(“ ABC”)到int(3))和折叠持续的数学表达式(例如60 * 60 * 24 to int(86400))。
>我们可以在此阶段以多种方式检查OpCode输出,包括OPCACHE,VLD和PHPDBG。我将使用VLD为此,因为我觉得输出更友好。>让我们看看以下file.php脚本的输出是什么:
>$code = <<<'code' <span><span><?php </span></span><span><span>$a = 1; </span></span><span>code<span>; </span></span><span> </span><span><span>$tokens = token_get_all($code); </span></span><span> </span><span><span>foreach ($tokens as $token) { </span></span><span> <span>if (is_array($token)) { </span></span><span> <span>echo "Line <span><span>{$token[2]}</span>: "</span>, token_name($token[0]), " ('<span><span>{$token[1]}</span>')"</span>, PHP_EOL; </span></span><span> <span>} else { </span></span><span> <span>var_dump($token); </span></span><span> <span>} </span></span><span><span>} </span></span>
登录后复制登录后复制Line 1: T_OPEN_TAG ('<?php ') Line 2: T_VARIABLE ('$a') Line 2: T_WHITESPACE (' ') string(1) "=" Line 2: T_WHITESPACE (' ') Line 2: T_LNUMBER ('1') string(1) ";"
登录后复制登录后复制> OPCACHE不仅可以简单地缓存OPCODE(因此绕过Lexing,解析和编译阶段)。它还包含许多不同级别的优化。让我们将优化级别提高到四个传球,以查看出来的内容:$code = <<<'code' <span><span><?php </span></span><span><span>$a = 1; </span></span><span>code<span>; </span></span><span> </span><span><span>print_r(ast<span>\parse_code</span>($code, 30)); </span></span>
登录后复制登录后复制>
>命令:>输出:
ast\Node Object ( [kind] => 132 [flags] => 0 [lineno] => 1 [children] => Array ( [0] => ast\Node Object ( [kind] => 517 [flags] => 0 [lineno] => 2 [children] => Array ( [var] => ast\Node Object ( [kind] => 256 [flags] => 0 [lineno] => 2 [children] => Array ( [name] => a ) ) [expr] => 1 ) ) ) )
登录后复制>我们可以看到恒定条件已被删除,并且两个回声指令已被压缩到单个指令中。这些只是对Opcache在脚本的Opcodes上进行的许多优化的味道。不过,我不会浏览本文的各种优化级别,因为这本身也是一篇文章。
>阶段4 - 解释<span>if (PHP_VERSION === '7.1.0-dev') { </span> <span>echo 'Yay', PHP_EOL; </span><span>} </span>
登录后复制>最后阶段是对opcodes的解释。这是Opcodes在Zend Engine(ZE)VM上运行的地方。对于这个阶段,实际上几乎没有什么可说的(至少从高级角度来看)。输出几乎是您通过echo,print,var_dump等命令输出输出的任何内容。
>因此,这是一个有趣的事实,而不是在此阶段挖掘任何复杂的事实:PHP在生成自己的VM时需要自己作为依赖性。这是因为VM是由PHP脚本生成的,因为它更简单并且更易于维护。结论
>我们已经简要介绍了PHP解释器在运行PHP代码时通过的四个阶段。这涉及使用各种扩展(包括令牌,PHP-ast,opcache和vld)来操纵和查看每个阶段的输出。
。>我希望本文能够帮助您对PHP的解释器有更好的整体理解,并显示了Opcache扩展的重要性(用于其缓存和优化能力)。
经常询问有关PHP执行过程的问题(常见问题解答)>
> PHP的命令行接口和Web服务器接口之间有什么区别? -line接口(CLI)和Web服务器接口是运行PHP脚本的两种不同方法。 CLI用于从命令行运行PHP脚本,而Web服务器接口则用于响应Web请求来运行PHP脚本。两个接口之间的主要区别是它们处理输入和输出的方式。在CLI中,从命令行读取输入,并将输出写入控制台。在Web服务器接口中,从HTTP请求读取输入,并将输出写入HTTP响应。>
PHP在执行过程中如何处理错误?php具有强大的错误处理。允许其在执行过程中处理错误的机制。发生错误时,PHP会生成错误消息并将其发送到错误处理程序。错误处理程序可以根据错误报告设置显示错误消息,将其记录或忽略。 PHP还支持异常处理,这使其可以以更结构化和易于管理的方式处理错误。 > > php扩展在执行过程中的作用是什么?
php扩展是在PHP语言中添加新功能和功能的模块。在执行过程中,它们被加载到PHP运行时环境中,可用于执行从数据库访问到图像处理的广泛任务。 PHP扩展名为C编写,并编译为机器代码,这使其非常快速有效。它们是PHP生态系统的关键组成部分,并有助于其灵活性和功率。
>> PHP如何优化执行过程?
PHP使用多种技术来优化执行过程。这些技术之一是OpCode缓存,其中涉及将PHP引擎生成的字节码存储在内存中,以便可以在后续执行中重复使用。这消除了每次执行PHP脚本的必要性,从而大大提高了性能。 PHP还使用Just-In-time(JIT)汇编,其中涉及在运行时将字节码编译到机器代码中以进一步提高性能。>
PHP在执行过程中如何处理内存管理? PHP具有内置内存管理器,可以在执行过程中处理内存分配和Deallocation。内存管理器根据需要为变量和数据结构分配内存,并在不再需要内存时对内存进行交易。 PHP还具有一个垃圾收集器,该垃圾收集器会自动释放不再使用的内存。这有助于防止内存泄漏并将内存使用控制在控制之下。> Web服务器在PHP执行过程中的作用是什么?>
> Web服务器在PHP执行中起关键作用过程。它负责处理HTTP请求,对这些请求运行PHP脚本,然后将HTTP响应发送回客户端。 Web服务器与PHP解释器和PHP引擎紧密合作,以执行PHP脚本并生成动态网页。 PHP最常用的Web服务器是Apache和Nginx。 MySQL,PostgreSQL和SQLite。它在执行过程中使用数据库特异性扩展与这些数据库进行交互。这些扩展提供了一组功能,可用于连接到数据库,执行SQL查询,获取结果并处理错误。 PHP还支持PDO(PHP数据对象)扩展名,该扩展提供了数据库交互的数据库-Nostic接口。> PHP在执行过程中如何处理会话管理?
PHP对会话管理具有内置支持,这使其可以在不同的HTTP请求之间维护状态。启动会话后,PHP会创建唯一的会话ID,并将其存储在客户端浏览器上的cookie中。然后,此会话ID通过每个后续请求发送回服务器,允许PHP识别客户端并检索相应的会话数据。 PHP的会话管理功能使在Web应用程序中实现用户身份验证,购物车和其他状态功能变得易于实现。
以上是PHP如何执行 - 从源代码到渲染的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

在PHPStorm中如何进行CLI模式的调试?在使用PHPStorm进行开发时,有时我们需要在命令行界面(CLI)模式下调试PHP�...

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。
