Deliverer 1.0.8 支持 PHP5 了

经历了两周的迭代,Deliverer 目前更新到了 1.0.8 https://github.com/zhoumengka...git

由于是为了解决祖传代码的问题,也听到群友的一些声音,仍是颇有必要支持下 PHP5 的,因此这段时间一直在着力解决这个版本兼容问题,没想到问题比较我预计的要难不少。github

记录下开发中遇到的问题(主要是体力活)也想分享以后,有兴趣的朋友能够fork一份以后,对代码不那么陌生,更期待各位个 PR微信

在 PHP7 中,函数或者方法在执行的时候都在zend_execute_data结构体中的execute_data->call->fbc中,而 PHP5 中对应的字段拿到的倒是调用该函数的函数,两者差距比较大。函数

后来发现 PHP5 zend_execute_dataopline中查到了当前执行的函数信息,但在 PHP5.4 先后逻辑还有差别,须要区别对待(还好编译器提示报错的字段)工具

#if PHP_VERSION_ID < 50400
#define OP1_FUNCTION_PTR(n) (&(n)->op1.u.constant)
#else
#define OP1_FUNCTION_PTR(n) ((n)->op1.zv)
#endif

初次调用解决了,发现内嵌的调用,又不在opline里面了,并且版本不同,取得地方也不同,而且和上面的 opline 的判断版本号还不同,这就只能靠体力来测了。指针

#if PHP_VERSION_ID < 50500
    if (execute_data->fbc != NULL)
    {
        fbc = execute_data->fbc;
    }
#else
    if (execute_data->call != NULL && execute_data->call->fbc != NULL)
    {
        fbc = execute_data->call->fbc;
    }
#endif

最终获取函数信息就是多层判断日志

zend_function *fbc;

#if PHP_VERSION_ID < 70000
#if PHP_VERSION_ID < 50500
    if (execute_data->fbc != NULL)
    {
        fbc = execute_data->fbc;
    }
#else
    if (execute_data->call != NULL && execute_data->call->fbc != NULL)
    {
        fbc = execute_data->call->fbc;
    }
#endif
    if (fbc == NULL)
    {
        fbc = get_function_from_opline(execute_data->opline);
    }
#else
    if (execute_data->call != NULL && execute_data->call->func != NULL)
    {
        fbc = execute_data->call->fbc;
    }
#endif

在从 opline 里查询到的只是函数的名字,须要再去全局函数表里找到对应的函数指针code

static zend_function *get_function_from_opline(zend_op *opline)
{
    zend_function *fbc;

    zval *function_name = OP1_FUNCTION_PTR(opline);

    if (Z_STRVAL_P(function_name) == NULL)
    {
        return NULL;
    }

    if (zend_hash_find(EG(function_table), Z_STRVAL_P(function_name), Z_STRLEN_P(function_name) + 1, (void **)&fbc) ==
        FAILURE)
    {
        return NULL;
    }

    return fbc;
}

总体来讲 PHP5 的处理要比 PHP7 复杂不少,这也说明 PHP7 作的更好了,点赞。开发

这些就是这几天的开发工做,可能还有不少实际的线上环境没有遇到过,若是你有兴趣,可使用这个工具来解决问题,也能够一块儿来完善这个小工具。get

下周或者下下周我将加上 watch 功能,支持函数和方法的参数打印。主要是类比 Java 的 Arthas ,由于在其中 trace 和 watch 功能是我最经常使用的,虽然 PHP 能够线上直接修改加日志,可是这样毕竟不规范,走发布流程又太慢,我想这个 watch 功能仍是颇有必要的,大概是

$ ./bin/deliverer -w foo -n 3

表示监控foo函数3次调用后退出,而且打印出deliverer-request-id和其入参,能够再根据deliverer-request-id查看完整的调用栈。

若是以为有这兴趣,就请给个星星吧,https://github.com/zhoumengka...

安装和使用上有任何问题,欢迎加我微信 zhoumengkang 前来骚扰,暗号:deliverer

相关文章
相关标签/搜索