php的异常跳转的分析

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

<?php
try {
    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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值