接下来说说php的生命周期。php_request_startup阶段类似于php_module_startup。是一个初始化工作,比php_module_startup要简单的多。你可以自己看看。关注php_execute_script的执行阶段。用gdb看调用栈,gdb./phpphp_execute_script断点,执行,看调用栈,bphp_execute_script(gdb)rtest.phpbt#0php_execute_script(primary_file=0x7fffffffe240)at/www/test/php/php-7.4.3/main/main.c:2541#10x00000000008bbd85在do_cli(argc=2,argv=0x1425af0)在/www/test/php/php-7.4.3/sapi/cli/php_cli.c:961#20x00000000008bcd2dinmain(argc=2,argv=0x1425af0)at/www/test/php/php-7.4.3/sapi/cli/php_cli.c:1356你可以清楚地看到调用堆栈中的执行过程,现在转到/cli/php_cli.c文件查看已完成的操作,intc;zend_file_handle文件句柄;int行为=PHP_MODE_STANDARD;char*reflection_what=NULL;易失性intrequest_started=0;易失性intexit_status=0;char*php_optarg=NULL,*orig_optarg=NULL;char*exec_direct=NULL,*exec_run=NULL,*exec_begin=NULL,*exec_end=NULL;char*arg_free=NULL,**arg_excp=&arg_free;char*script_file=NULL,*translated_pa??th=NULL;int交互=0;int线号=0;constchar*param_error=NULL;inthide_argv=0;zend_try{CG(in_compilation)=0;/*未初始化但需要几个选项*/while((c=php_getopt(argc,argv,OPTIONS,&php_optarg,&php_optind,0,2))!=-1){switch(c){初始化变量,解析命令到/main/main.c文件看真正的执行阶段PHPAPIintphp_execute_script(zend_file_handle*primary_file){zend_file_handle*prepend_file_p,*append_file_p;zend_file_handleprepend_file={{0},NULL,NULL,0,0},append_file={{0},NULL,NULL,0,0};#ifHAVE_BROKEN_GETCWDvolatileintold_cwd_fd=-1;#elsechar*old_cwd;ALLOCA_FLAG(use_heap)#endifintretval=0;加载要执行的php文件,通过zend_compile_file进行词法分析和语法分析,生成AST,编译成op_array,也就是指令集,我们看指令集,bzend_executecbt(gdb)p*op_array$1={type=2'\002',arg_flags="\000\000",fn_flags=37748736,function_name=0x0,范围=0x0,原型=0x0,num_args=0,required_num_args=0,arg_info=0x0,cache_size=16,last_var=2,T=4,last=13,操作码=0x7ffff5e8b000,run_time_cache__ptr=0x0,static_variables_ptr__ptr=e7varfff55=0x0,vars=0x7ffff5e790f0,refcount=0x7ffff5e85000,last_live_range=0,last_try_catch=0,live_range=0x0,try_catch_array=0x0,filename=0x7fffff5e583c0=0x7fff5E583c0=0x7fff5efff5efff5e__start=1tocry_start=1lithyfly=1lithyfly=1lithyfly=1lithyfly=1lirs_start=1lirnfly=1lirnfly=1,,reserved={0x0,0x0,0x0,0x0,0x0,0x0}}然后放到zend虚拟机上执行zend_execute(op_array,retval);这里可以看到真正执行的是这个zend_execute_ex(execute_data);,它是一个函数指针,我们可以替换它,知道了这一点,那么我们在写扩展的时候就可以重写一个zend_execute_ex函数来替换默认的php函数,而我们的自己可以做很多事情,比如拦截php函数,做性能监控。请求关闭阶段php_request_shutdown,模块关闭阶段php_module_shutdown这两个阶段主要是变量销毁,现在我们知道了自定义扩展在生命周期中是如何执行的
