PHP的运行机制及原理

    1. 我们从未手动开启过PHP的相关进程,它是随着Apache的启动而运行的;

    1. PHP通过SAPI和Apache相连;

    1. PHP总共有三个模块:内核、Zend引擎、以及扩展层;

    1. PHP内核用来处理请求、文件流、错误处理等相关操作;

    1. Zend引擎(ZE)用以将源文件转换成机器语言,然后在虚拟机上运行它;

    1. 扩展层是一组函数、类库和流,PHP使用它们来执行一些特定的操作。比如,我们需要mysql扩展来连接MySQL数据库;

    1. 当ZE执行程序时可能会需要连接若干扩展,这时ZE将控制权交给扩展,等处理完特定任务后再返还;

    1. 最后,ZE将程序运行结果返回给PHP内核,它再将结果传送给SAPI层,最终输出到浏览器上。

php执行过程

1.扫描(scanning) ,将index.php内容变成一个个语言片段(token)

2.解析(parsing) , 将一个个语言片段变成有意义的表达式

3.编译(complication),将表达式编译成中间码(opcode)

4.执行(execution),将中间码一条一条的执行

5.输出(output buffer),将要输出的内容输出到缓冲区

学过编译原理的应该了解Lex , Lex是LEXical compiler的缩写,是个非常著名的工具,主要功能是词法分析器(scanner),描述规则采用正则表达式(regular expression)。在php源码中是 Zend/zend_language_scanner.c 去根据 Zend/zend_language_scanner.l (lex规则文件) ,来对需要执行的php文件进行词法分析 ,从而得到一个个的"词" (token),当然执行规则,也就是切分的方式还是用正则表达式做的

具体看代码 Zend/zend_language_scanner.l

$code =<<<'PHP_CODE'
<?php
//这是注释
echo "Hello, world\n";
$data = 1 + 1;
echo $data;
PHP_CODE;


print_r(token_get_all($code));

分析这个返回结果我们可以发现,源码中的字符串,字符,空格,都会原样返回。每个源代码中的字符,都会出现在相应的顺序处。每一个数组的结构都是一致的,

Array(
     [0] => 316                 //tokenid,也就是"词"id 
     [1] => "Hello, world\n"        //"词"具体的内容
      [2] => 3                //所在的位置,行数
)

Token ID (在Zend内部的改Token的对应码,比如,T_ECHO,T_STRING)。

具体的定义可以在zend_language_parser.h中找到

解析 parsing

词法分析后, 就需要根据一个个token去组成有意义的表达式

Parsing首先会丢弃Tokens Array中的多余的空格,然后将剩余的Tokens转换成一个一个的简单的表达式,例如上例中:

1.输出一个常量字符串

2.两个数字相加

3.上个表达式的结果存储在一个变量

4.输出这个变量

编译 complication

根据上面的表达式,我们要将之编译成中间码(opcode),编译成opcode后,zend引擎才会根据一条一条的opcode 去执行我们的功能!

我们怎么看到编译后的opcode代码呢? 可以用vld扩展或者parsekit相关函数可以看到编译后的opcode,上例中的opcode:

* ZEND_ECHO     'Hello World'
* ZEND_ADD       ~0 1 1  
* ZEND_ASSIGN  !0 ~0
* ZEND_ECHO     !0

注意: 1+1操作完成结果要存起来,存到临时变量 ~0 将~0赋值给$c也就是!0;

执行 execution

执行的工作具体由 Zend/zend_execute.c 来完成

如果执行是某内置函数或语句,例如array_search,会调用对应的array函数.

如果调用的是扩展,例如mysqli或pdo,则会将控制权交给这些扩展,扩展执行完后将记过返回给ZE.

全部执行完后ZE将结果返回php内核,内核再返回SAPI,最后返回到服务器,通过服务器httpresponse返回到浏览器

如何让PHP的网站运行的更快?

  • 压缩代码,去除无用的注释或空白

  • 尽量使用PHP内置函数或扩展函数

  • 用apc/xcache/opcache等缓存PHP的opcode

  • 使用多线程、多进程优化程序逻辑

  • 缓存复杂和耗时运算的结果

  • 能异步处理的任务不要马上处理,如发邮件

  • 依据资源情况对FastCGI配置合适的参数

Last updated