> For the complete documentation index, see [llms.txt](https://phper.shujuwajue.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://phper.shujuwajue.com/phpxuan-xiang-he-yun-xing-yuan-li/phpde-yun-xing-ji-zhi-ji-yuan-li.md).

# 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),将要输出的内容输出到缓冲区

![](/files/-LfnTHeLDfGgJLiDbfYo)扫描 **scanning**

学过编译原理的应该了解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

```php
$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配置合适的参数


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://phper.shujuwajue.com/phpxuan-xiang-he-yun-xing-yuan-li/phpde-yun-xing-ji-zhi-ji-yuan-li.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
