php的异常跳转的分析

来源:互联网 发布:java 对称加密 编辑:程序博客网 时间:2024/04/25 17:59

这篇博客很简单,是写给自己的,每天写一篇博客的习惯要继续。今天的博文写的主要是php中异常条转的分析。先写一段PHP的代码吧:

<?phptry {    echo 'step exception one';//flag1    try {        echo 'step exception two';//flag2        try {            echo 'step exception three';//flag3            throw new Exception("exception");        }catch(Exception $e) {            throw $e;        }    } catch (Exception $e) {        throw $e;    }} catch(Exception $e) {    echo "catch the exception now";}?>

上面我们使用了3个try语句,异常一层层往上抛,PHP如何去捕获这些异常,PHP内部如何做到抛出异常。我们知道在C语言中,jmp类族函数可以实现跨函数跳转,因此我们写个简单的例子:

#include <stdio.h>#include <setjmp.h>jmp_buf buf;void step2(){   puts("now we are in step2");   longjmp(buf, 2);}void step1(){    puts("now we are in step1");    if(setjmp(buf) == 0) {        puts("set jump in step1");        step2();    } else {        puts("catch the jump");    }}int main(int argc, char **argv){   /**    *the results:    *now we are in step1    *set jump in step1    *now we are in step2    *catch the jump    */    step1();    return 0;}

现在我们在加一层跳转,来模拟上述PHP的三个try catch,这个时候我们需要记录下上一步的

#include <setjmp.h>jmp_buf *buf;void step3(){    longjmp(*buf, 3);}void step2(){   puts("now we are in step2");   jmp_buf *old_buf = buf;   jmp_buf now_buf;   if(setjmp(now_buf) == 0) {      buf = &now_buf;      step3();   } else {      //我们可以处理异常,也可以继续往上抛 类似于 throw      longjmp(*old_buf, 2);   }}void step1(){    puts("now we are in step1");    jmp_buf *old_buf;    jmp_buf now_buf;    if(setjmp(now_buf) == 0) {        puts("set jump in step1");        buf = &now_buf;        step2();    } else {        puts("catch the jump");    }}//这样我可以一层层往上跳转,buf 记录上一步的jmp_buf的地址。PHP就是这样实现异常的往上逐层抛。

PHP的内部封装:

//在zend_globals.h中的struct _zend_executor_globals {    //...       JMP_BUF *bailout;//类似我们上边的buf,称之为中继指针    //...};//zend_portability.h定义了#ifdef HAVE_SIGSETJMP# define SETJMP(a) sigsetjmp(a, 0)# define LONGJMP(a,b) siglongjmp(a, b)# define JMP_BUF sigjmp_buf#else# define SETJMP(a) setjmp(a)# define LONGJMP(a,b) longjmp(a, b)# define JMP_BUF jmp_buf#endif//在zend.h中有定义 try之类的定义#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

下一篇博客我们分析一下sigsetjmp siglongjmp这2个函数吧。

0 0
原创粉丝点击