美文网首页PHP经验分享php扩展开发
php源码-die、exit函数执行过程

php源码-die、exit函数执行过程

作者: cc180912 | 来源:发表于2018-12-25 15:51 被阅读10次

在php代码中我们会通过 die、exit函数来中断程序的执行,但是在fpm sapi模式下,这两个函数的执行并不会导致进程的退出,仅仅是结束当前request,这是如何做到的呢,要解答这个问题就要了解die、exit函数的执行原理

下面以exit为例说明, die函数和exit编译完后是同一个opcode

首先,我们定位下exit 的opcode handler函数, 不知道如何查找opcode handler的参考下这篇文章 php源码-如何查看opcode源码

exit对应的 opcode handler是 ZEND_EXIT_SPEC_UNUSED_HANDLER

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_EXIT_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
    USE_OPLINE

    SAVE_OPLINE();
    if (IS_UNUSED != IS_UNUSED) {

        zval *ptr = NULL;

        do {
            if (Z_TYPE_P(ptr) == IS_LONG) {
                EG(exit_status) = Z_LVAL_P(ptr);
            } else {
                if ((IS_UNUSED & (IS_VAR|IS_CV)) && Z_ISREF_P(ptr)) {
                    ptr = Z_REFVAL_P(ptr);
                    if (Z_TYPE_P(ptr) == IS_LONG) {
                        EG(exit_status) = Z_LVAL_P(ptr);
                        break;
                    }
                }
                zend_print_variable(ptr);
            }
        } while (0);

    }
    zend_bailout();  //关键所在
    ZEND_VM_NEXT_OPCODE(); /* Never reached */
}

这个函数里只有一句关键的代码,就是zend_bailout(), zend引擎就是通过这个来实现程序的中断的

#define zend_bailout()      _zend_bailout(__FILE__, __LINE__)

ZEND_API ZEND_COLD void _zend_bailout(char *filename, uint lineno) /* {{{ */
{

    if (!EG(bailout)) {
        zend_output_debug_string(1, "%s(%d) : Bailed out without a bailout address!", filename, lineno);
        exit(-1);
    }
    CG(unclean_shutdown) = 1;
    CG(active_class_entry) = NULL;
    CG(in_compilation) = 0;
    EG(current_execute_data) = NULL;
    LONGJMP(*EG(bailout), FAILURE); //关键点在这里, 
}


# define SETJMP(a) setjmp(a)
# define LONGJMP(a,b) longjmp(a, b)

可以看到 zend_bailout 实际上执行的是 longjmp 。setjmp,longjmp 是C语言提供的标准异常处理模式,实现程序跳转。

那么 LONGJMP(*EG(bailout), FAILURE) 最终是跳到哪里去了呢 ?

以fpm sapi为例, 在 fpm_main.c中可以找到 php_execute_script() 函数的调用, 这个函数在fpm模式下,每个request都会调用一次

PHPAPI int php_execute_script(zend_file_handle *primary_file){
        zend_try {
                  ...
                  zend_execute_scripts()
                  ...
        }zend_end_try();
}

这里的关键就是 zend_try、zend_catch、zend_end_try 这三个宏是zend提供的处理异常和 die、exit这种函数的方法,其中zend_try 中就调用了 SETJMP 来设置 "跳转位置"

还有一个zend_first_try, 这个和zend_try的唯一区别是多了EG(bailout)=NULL;这么一句, 一般这个只在sapi启动的最开始调用一次

//zend.h 文件

#define zend_try                                                \
    {                                                           \
        JMP_BUF *__orig_bailout = EG(bailout);                  \
        JMP_BUF __bailout;                                      \
                                                                \
        EG(bailout) = &__bailout;                               \
        if (SETJMP(__bailout)==0) {
#define zend_catch                                              \
        } else {                                                \
            EG(bailout) = __orig_bailout;
#define zend_end_try()                                          \
        }                                                       \
        EG(bailout) = __orig_bailout;                           \
    }
#define zend_first_try      EG(bailout)=NULL;   zend_try

相关文章

  • php源码-die、exit函数执行过程

    在php代码中我们会通过 die、exit函数来中断程序的执行,但是在fpm sapi模式下,这两个函数的执行并不...

  • PHP操作SQL常用tips

    PHP基础语法 PHP常用函数 die($str):终止当前PHP文件的执行,并向客户端输出一个终止的原因说明@:...

  • 深入理解php内核学习笔记之一

    1.今天我们来学习用户代码的执行过程。 php代码的执行过程可以描述为下图 2.php的构成: php的源码有这些...

  • 手动推出

    exit(0);和abort(); exit和abort都是终止程序执行退出的处理函数,其中exit是正常退出,a...

  • YII2-PHPExcel

    php导出excel表格后有无法读取的内容 在save之后一定要紧跟die()或者是exit() $objWrit...

  • Handler

    一、Handler简单使用 二、源码中的执行过程 Handler的主要函数 MessageQueue的执行过程en...

  • iOS 仿安卓平滑退出应用或进程退出(exit、_exit、ab

    import Foundation exit和abort都是终止程序执行退出的处理函数,其中exit是正常退出,a...

  • 2018-10-21

    进程终止 exit(int) 执行若干清理活动之后调用 _Exit(int) 返回内核。等价于主函数 return...

  • [CTF_web]exec/exec1.php

    CTF_web CTF_web 源码如下 : php exec 函数可以同时执行多个命令 , 只需要用 \n 分隔...

  • PHP 错误消息处理 & 异常消息处理 -- (学习笔记

    PHP 错误处理1、使用 die() 函数 2、使用 trigger_error() 函数在脚本中用户输入数据的位...

网友评论

    本文标题:php源码-die、exit函数执行过程

    本文链接:https://www.haomeiwen.com/subject/tiuflqtx.html