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

相關文章
相關標籤/搜索