php内核分析(二)
摘要:这里阅读的php版本为PHP-7.1.0 RC3,阅读代码的平台为linuxZTS我们会看到文章中有很多地方是:#ifdef ZTS # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v) #else # define CG(v) (compi ...
这里阅读的php版本为PHP-7.1.0 RC3,阅读代码的平台为linux
ZTS
我们会看到文章中有很多地方是:
1 #ifdef ZTS 2 # define CG(v) ZEND_TSRMG(compiler_globals_id, zend_compiler_globals *, v) 3 #else 4 # define CG(v) (compiler_globals.v) 5 extern ZEND_API struct _zend_compiler_globals compiler_globals; 6 #endif
这里的ZTS是个什么概念呢。我们经常使用的php都是运行在单进程,单线程环境,比如cgi,都是一个请求进来,就一个进程为它服务,当请求结束了,进程也就结束了。所以比如像全局变量,php内核就没有考虑多线程同时修改获取的时候线程安全问题。后来,php渐渐也在往单进程多线程服务器方向发展。那么这个时候,就会需要有一个层来专门处理线程安全问题。这个就是TSRM(Thread Safe Resource Management)。
但是php默认是关闭线程安全的。在编译的时候,你可以指定参数开启编译一个线程安全版本的php。(--enable-maintainer-zts 选项, Windows 平台为 --enable-zts)这个就是这里的ZTS的由来。
比如上面的例子,CG(V) 在非线程安全下获取的是全局结构compiler_globals结构的v属性,在线程安全下获取的是通过ZEND_TSREMG方法来获取。
zend_try
我们会看到zend_try_catch相关的代码如下:
1 zend_try { 2 ...exec_try 3 } zend_catch { 4 ...exec_catch 5 } zend_end_try();
把宏展开,我们可以看到大概代码如下:
01 { \ 02 JMP_BUF *__orig_bailout = EG(bailout); \ 03 JMP_BUF __bailout; \ 04 \ 05 EG(bailout) = &__bailout; \ 06 if (SETJMP(__bailout)==0) { 07 { 08 ...exec_try 09 } 10 } else { \ 11 EG(bailout) = __orig_bailout; 12 { 13 ...exec_catch 14 } 15 } \ 16 EG(bailout) = __orig_bailout; \ 17 }
这个是什么意思呢,需要先理解下setjmp和longjmp,这两个函数是linux提供的方法。他们是组合起来使用的,达到协同程序的功能
#include
#include
jmp_buf env;
void foo() {
printf("before jmp\n");
int ret = setjmp(env);
if(ret == 0) {
return;
} else {
printf("return %d\n", ret);
}
printf("after jmp\n");
}
int main(int argc, char* argv[]) {
foo();
longjmp(env, 999);
return 0;
}// 输出:
/* before jmp
return 999
after jmp */
上面的这个例子,setjmp的时候相当于程序片段1把主动权交出来,然后执行if(ret == 0)下面的程序,直到遇到longjmp,把执行权还给了片段1,并且设置jmp_buf为999,片段1继续执行,发现了ret!=0,就输出return 999。
好了,回到这个程序:
01 { \ 02 JMP_BUF *__orig_bailout = EG(bailout); \ 03 JMP_BUF __bailout; \ 04 \ 05 EG(bailout) = &__bailout; \ 06 if (SETJMP(__bailout)==0) { 07 { 08 ...exec_try 09 } 10 } else { \ 11 EG(bailout) = __orig_bailout; 12 { 13 ...exec_catch 14 } 15 } \ 16 EG(bailout) = __orig_bailout; \ 17 }
这个程序里面的exec_try代码段里面,在遇到错误的时候,需要返回的时候,就会包含一个longjmp函数的调用。这样,就形成了我们平时调用try...catch...finnal的功能:
1 先保存全局变量里面的bailout
2 使用setjmp来做跳转执行下面的程序
3 执行exec_try
4 如果exec_try这个代码段里面有longjmp,并且longjmp返回非0(一般也确实非0),就执行exec_catch
5 最后,把全局变量里面的bailout恢复
这里可能会有两个疑惑,如果exec_try里面没有longjmp怎么办,那就直接只执行了exec_try,就跳过exec_catch了。这个也是标准的用setjmp和longjmp实现try catch的写法。
这两个的实现弥补了goto关键字只能在函数内部进行跳转的限制。这个叫做“长跳转”。
所以在PHP代码中,如果你执行的函数有可能抛出异常。不妨使用这个方式把你要执行的程序放在里面。
以上就是php内核分析(二)的内容,更多相关内容请关注PHP中文网(www.php.cn)!

热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

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

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

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

Dreamweaver CS6
视觉化网页开发工具

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

热门话题

PHP 8.4 带来了多项新功能、安全性改进和性能改进,同时弃用和删除了大量功能。 本指南介绍了如何在 Ubuntu、Debian 或其衍生版本上安装 PHP 8.4 或升级到 PHP 8.4

Visual Studio Code,也称为 VS Code,是一个免费的源代码编辑器 - 或集成开发环境 (IDE) - 可用于所有主要操作系统。 VS Code 拥有针对多种编程语言的大量扩展,可以轻松编写

如果您是一位经验丰富的 PHP 开发人员,您可能会感觉您已经在那里并且已经完成了。您已经开发了大量的应用程序,调试了数百万行代码,并调整了一堆脚本来实现操作

本教程演示了如何使用PHP有效地处理XML文档。 XML(可扩展的标记语言)是一种用于人类可读性和机器解析的多功能文本标记语言。它通常用于数据存储

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

字符串是由字符组成的序列,包括字母、数字和符号。本教程将学习如何使用不同的方法在PHP中计算给定字符串中元音的数量。英语中的元音是a、e、i、o、u,它们可以是大写或小写。 什么是元音? 元音是代表特定语音的字母字符。英语中共有五个元音,包括大写和小写: a, e, i, o, u 示例 1 输入:字符串 = "Tutorialspoint" 输出:6 解释 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。总共有 6 个元

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

PHP的魔法方法有哪些?PHP的魔法方法包括:1.\_\_construct,用于初始化对象;2.\_\_destruct,用于清理资源;3.\_\_call,处理不存在的方法调用;4.\_\_get,实现动态属性访问;5.\_\_set,实现动态属性设置。这些方法在特定情况下自动调用,提升代码的灵活性和效率。
