PHP内核之旅-2.SAPI中的Cli

一、SAPI是什么?

1.1 理解SAPI

(1)SAPI是PHP框架的接口层。有很多种服务器的SAPI的实现,代码在sapi文件夹下。常见的接口抽象层实现有:cgi,apache2,cli,embed,fpm。

(2)各个服务器遵循着相同的约定,每个服务器的SAPI实现都有一套自己的实现。由于很多操作都是相同的,所以有一部分使用的是默认方法。

(3)SAPI类似面向对象中的模板方法模式的应用。 SAPI.c和SAPI.h文件所包含的一些函数就是模板方法模式中的抽象模板, 各个服务器对于sapi_module的定义及相关实现(cli,fpm,apache2)则是一个个具体的模板。

sapi在源代码中的路径如下:

1.2 调用SAPI实现的接口的示意图

上层调用可以是命令行窗口执行php脚本,然后到SAPI接口层,然后具体执行php脚本的是cli(Command Line Interface)接口的方法。

我们就以最简单的SAPI接口Cli来讲SAPI的实现。

二、Cli是什么?

Cli即命令行接口,当在命令行窗口下执行php脚本时,则会调用Cli。

2.1 直接执行脚本文件

在命令行窗口执行test.php脚本
$ php test.php

还可以传递一些指定的参数,比如

2.2 -r: 直接执行php代码

设置变量$a = 123,然后打印变量$a的值,并回车换行
$ php -r '$a=123; echo $a . "\r\n";'
打印结果:123

2.3 -v: 打印php的版本号

user@wt01084-048:~$ php -v
PHP 7.2.2-3+ubuntu14.04.1+deb.sury.org+1 (cli) (built: Feb  6 2018 16:35:00) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.2.2-3+ubuntu14.04.1+deb.sury.org+1, Copyright (c) 1999-2018, by Zend Technologies

三、Cli的执行流程?

 Cli是单进程模式。处理完请求就关闭了。

生命周期:

核心代码:

main函数位于文件:\sapi\cli\php_cli.c

伪代码如下:

 1 main()
 2 {
 3     // 1.初始化变量
 4     ...
 5     
 6     // 2.定义sapi_module,它是记录SAPI信息的主要结构。
 7     // 结构体类型为_sapi_module_struct,在\main\SAPI.h定义了结构体_sapi_module_struct类型。
 8     sapi_module_struct *sapi_module = &cli_sapi_module;
 9     
10     // 3.初始化sapi_module
11     sapi_startup(sapi_module); //sapi_startup函数位于\main\SAPI.c
12 
13 
14     // 4.模块初始化阶段
15     sapi_module->startup(sapi_module); //这里的startup在结构体_sapi_module_struct类型中有定义,
16                                         //而Cli定义的cli_sapi_module的结构体中php_cli_startup指向了startup,所以其实就是调用了php_cli_startup
17                                         //而php_cli_startup直接调用了php_module_startup()
18     
19     // 5.请求初始化及执行请求
20     do_cli();
21         // 5.1 根据命令行指定的参数执行相应的操作,如果是查询系统信息之类的请求(-i、-m、-v),则会跳过请求初始化阶段
22         switch ($args) {
23             ...
24         }
25         // 5.2 请求初始化
26         php_request_startup()
27         // 5.3 执行脚本
28         switch (behavior) {
29             case PHP_MODE_STANDARD: //标准执行模式,执行脚本文件
30                 php_execute_script(&file_handle);
31                 break;
32             case ...//其他执行模式
33         }
34         // 5.4.请求关闭阶段
35         out:
36             php_request_shutdown((void *) 0);
37     
38     // 6.模块关闭阶段
39     php_module_shutdown();
40     sapi_shutdown();
41 }

参考资料:http://www.php-internals.com/

作  者: Jackson0714 出  处:http://www.cnblogs.com/jackson0714/ 关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教! 版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。 特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我 声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是作者坚持原创和持续写作的最大动力!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏*坤的Blog

公司web安全等级提升

公司的一个web数据展示系统,本来是内网的,而且是一个单独的主机,不存在远程控制的问题,所以之前并没有考虑一些安全相关的测试.但是国调安全检查的需要添加这样子的...

884
来自专栏LuckQI

学习Java基础知识,打通面试关~十三锁机制

1155
来自专栏java达人

ThreadLocal与Spring 事务管理

编写线程安全代码的关键是管理程序中的共享可变状态,除了通过synchronized加锁机制防止多个线程同时访问同一段数据外,还有一种方法就是通过ThreadLo...

20710
来自专栏向治洪

Android 使用android-support-multidex解决Dex超出方法数的限制问题

随着应用不断迭代,业务线的扩展,应用越来越大(比如集成了各种第三方sdk或者公共支持的jar包,项目耦合性高,重复作用的类越来越多),相信很多人都遇到过如下的...

3008
来自专栏lgp20151222

rabbit的简单搭建,java使用rabbitmq queue的简单例子和一些坑

由于本人的码云太多太乱了,于是决定一个一个的整合到一个springboot项目里面。

1611
来自专栏坚毅的PHP

jersey处理支付宝异步回调通知的问题:java.lang.IllegalArgumentException: Error parsing media type 'application/x-www

tcpflow以流为单位分析请求内容,非常适合服务器端接口类服务查问题 这次遇到的问题跟支付宝支付后的回调post结果有关 淘宝的代码例子: publi...

5045
来自专栏吴伟祥

Redis分布式锁的正确实现方式(Java版)

分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis...

732
来自专栏比原链

Derek解读Bytom源码-启动与停止

Gitee地址:https://gitee.com/BytomBlockchain/bytom

1013
来自专栏YouMeek

一个Java程序员眼中的Mac OS(系列六:终端方案iTerm2 + Zsh)

本文初衷 整理自己脑袋中、收藏中的那些资料,来一次清空,让自己重新开始。 帮助 Mac 后来者,减少他/她入门成本 如果你不是后台开发者,一般不需要用到这个东西...

3668
来自专栏实战docker

修改,编译,GDB调试openjdk8源码(docker环境下)

在上一章《在docker上编译openjdk8》里,我们在docker容器内成功编译了openjdk8的源码,有没有读者朋友产生过这个念头:“能不能修改open...

4179

扫码关注云+社区