>  기사  >  백엔드 개발  >  Deliverer 1.0.8은 이미 PHP5를 지원합니다!

Deliverer 1.0.8은 이미 PHP5를 지원합니다!

藏色散人
藏色散人앞으로
2021-07-05 16:14:211299검색

2주간의 반복 작업 끝에 현재 Deliverer는 1.0.8로 업데이트되었습니다. PHP5 지원이 여전히 필요하다는 친구들의 목소리도 들었고, 이 기간 동안 이 버전 호환성 문제를 해결하기 위해 열심히 노력해 왔는데, 예상보다 문제가 훨씬 더 어렵습니다.

개발(주로 육체 작업) 중에 발생한 문제를 기록하고 공유하고 싶은 경우
관심 있는 친구들이 복사본을 fork하여 코드에 대한 낯설음을 덜 수 있기를 바랍니다

. .

PHP7에서 함수나 메소드는 실행될 때 zend_execute_data 구조의 execute_data->call->fbc에 있는 반면, PHP5에서는 해당하는 것 필드가 얻는 것 는 함수를 호출하는 함수이며 둘 사이의 차이는 상대적으로 큽니다. 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 里查询到的只是函数的名字,需要再去全局函数表里找到对应的函数指针

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 做的更好了,点赞。

这些就是这几天的开发工作,可能还有很多实际的线上环境没有遇到过,如果你有兴趣,可以使用这个工具来解决问题,也可以一起来完善这个小工具。

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

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

表示监控foo函数3次调用后退出,并且打印出deliverer-request-id和其入参,可以再根据deliverer-request-id 나중에 확인해보니 현재 실행되는 함수 정보가 PHP5 zend_execute_dataopline에서 발견되었는데, PHP5.4 전후의 로직에 차이가 있어서 꼭 확인해야 합니다. 다르게 처리됨 (다행히 컴파일러 오류가 발생한 필드)

rrreee

첫 번째 호출은 해결되었으며, 포함된 호출이 opline에 없고 버전도 다르고 위치도 다른 것으로 확인되었습니다. 어디서 얻었는지가 달랐고 위의 opline의 판단과 일치했습니다. 버전 번호는 여전히 다르기 때문에 물리적인 힘에 의존해서만 측정할 수 있습니다.

rrreee

함수 정보의 최종 획득은 다층 판단

rrreee

opline에서 쿼리하는 것은 함수 이름뿐이고 전역 함수 테이블에서 해당 함수 포인터를 찾아야 합니다rrreee일반적으로 , PHP5는 PHP7보다 더 잘 처리됩니다. 훨씬 더 복잡합니다. 이는 또한 PHP7이 더 잘 수행되고 있음을 보여줍니다.

이것은 지난 며칠 동안의 개발 작업입니다. 실제로 접하지 못한 온라인 환경이 많이 있을 수 있습니다. 관심이 있으시면 이 도구를 사용하여 문제를 해결하거나 이 가젯을 개선하기 위해 함께 작업할 수 있습니다. . 🎜🎜다음주나 다음주에 함수와 메서드의 매개변수 인쇄를 지원하는 시계 기능을 추가할 예정입니다. 주로 Java의 Arthas에 비유하자면, 제가 가장 많이 사용하는 기능은 추적 기능과 감시 기능입니다. PHP는 온라인에서 직접 로그를 수정하고 추가할 수 있지만 이는 결국 표준화되어 있지 않으며, 감시 기능이 너무 느린 것 같습니다. 여전히 매우 필요합니다. 아마도 🎜rrreee🎜는 foo 함수를 모니터링하여 3번의 호출 후에 종료하고 deliver-request-id 및 해당 입력 매개변수를 인쇄하는 것을 의미합니다. 그런 다음 deliver-request-id를 기반으로 전체 호출 스택을 봅니다. 🎜🎜이것에 관심이 있으시면 별표를 주세요 https://github.com/zhoumengkang/deliverer🎜🎜설치 및 사용에 문제가 있으면 WeChat zhoumengkang에 저를 추가해 와서 괴롭히세요, 비밀번호 : Deliverer🎜🎜 추천 학습: "🎜PHP 비디오 튜토리얼🎜"🎜🎜

위 내용은 Deliverer 1.0.8은 이미 PHP5를 지원합니다!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제