1.builtin types
基本定义在Zend/zend_types.h和Zend/zend.h中
主要的几种:
- 原始类型:zend_bool,zend_uchar,zend_intptr_t..
- 封装的用户直接接触的类型
zend_string,zend_array(HashTable),zend_object,zend_resource,zend_function.. - 内部使用:
zval,zend_value,zend_class_entry,zend_reference,zend_refcounted,zend_ast,zend_ast_ref,Bucket,zend_execute_data,HashTableIterator..
基本上是围绕以上几种类型构建整个数据操作的,尤其是
zend_object,HashTable,zend_string,zval的操作很常用
2.a couple of important globals
整个PHP环境和Zend环境会涉及多个全局变量,下面是几个比较重要的:
- php_core_globals core_globals(main/php_globals.h) ==> PG PHP调度sapi和zend engine的整个环境的全局变量存放位置
- sapi_globals_struct sapi_globals(main/SAPI.c) ==> SG SAPI模块的环境变量,主要是包括每次PHP请求的数据
- zend_compiler_globals compiler_globals(Zend/zend_compile.c) ==> CG Zend engine 编译过程需要的全局变量
- zend_executor_globals executor_globals(Zend/zend_compile.c) ==> EG Zend engine 执行过程中需要的全局变量
- zend_alloc_globals alloc_globals(Zend/zend_alloc.c) ==> AG Zend engine memory management globals
- zend_gc_globals gc_globals(Zend/zend_gc.c) ==> GC_G Zend engine gc related globals
- module globals(用Zend/zend_API.h中的DECLARE宏定义在相应模块中) ==> PHP扩展模块的全局变量
以上几个全局变量基本是从PHP环境到SAPI环境到Zend engine编译执行以及我们写自己的扩展时会涉及到的。
3.sapi
sapi模块主要是提供一套外界使用zend engine的统一接口,提供不同的服务模式,比如典型的几个模式:
- cli
- cgi
- apache module
不同的服务模式在模块的初始化,请求的初始化不太相同,对于服务类的通常只需要初始化一次sapi模块,sapi_startup–>sapi_module.startup
包括上述全局变量/PHP扩展模块初始化/Zend扩展的初始化等,之后只需要针对每次请求调用php_request_startup,zend_activate,sapi_activate,来激活request,sapi,zend engine,重新设置请求的数据,响应请求。
4.startup process
基本调用流程:
//初次调用流程
- sapi_startup(&sapi_module)
- sapi_module.startup()
- php_module_startup()
- sapi_activate()
- gc_global_ctor()
- zend_startup()
- zend_mm_startup()
- sapi_deactivate()
//请求流程
- php_request_startup()
- zend_activate()
- init_gc()
- init_compiler()
- init_executor()
- sapi_activate()
- php_request_shutdown()
- zend_deactivate()
- sapi_deactivate()
- or full zend_memory_shutdown
- or sapi_module.shutdown
5.memory manager
(1)内存管理相关的重要数据结构
- zend_mm_heap
- zemd_mm_storage
- zend_mm_chunck
- zend_mm_page
- zend_mm_page_map
- zend_mm_bin
- zend_arena
- zend_mm_huge_list
- zend_mm_free_slot
(2)sapi模块第一次初始化时:
- zend_mm_startup
- alloc_globals_ctor
- zend_mm_init初始化zend_mm_heap,分配main_chunck,并初始化main_chunck中的zend_mm_heap结构体,
main_chunck负责存储相关信息,只有main_chunck使用了heap结构体,并将heap与AG(mm_heap)挂接
(3)每次请求init_compiler时分配zend_memory_arena
- init_compiler
- zend_arena_create(64M) 放入CG(arena)
- emalloc
- _emalloc
- zend_mm_alloc_heap(AG(mm_heap)…)
- < 3072字节 zend_mm_alloc_small
- 根据size计算free_slots中是否还有空的小块item,如果有直接返回指针,否则zend_mm_alloc_small_slow
- zend_mm_alloc_pages根据bin_pages数组得到需要分配的页面,
如果空闲页面不足则重新zend_mm_chunck_alloc(mmap)分配chunck
- < 2M-4096字节 zend_mm_alloc_large
- 直接使用zend_mm_alloc_pages分配
- zend_mm_alloc_huge
- 使用zend_mm_chunck_alloc,加入heap的hugeblock_list
6.compiler and executor
(1)编译接口及编译流程:
- zend_eval_string(zend_execute_API.c)
- zend_eval_stringl
- zend_compile_string(zend_compile.c)
- compile_string(zend_language_scanner.c)
- zendparse(就是yyparse)(zend_language_parse.y) ==> 通过parser调用lexer,生成抽象语法树ast_list,存到CG(ast)
- zend_compile_top_stmt ==> 编译ast生成oparray
- pass_two(oparray) ==> 优化?
(2)执行流程
- zend_execute(zend_vm_execute.h)
- zend_vm_stack_push_call_frame
- i_init_execute_data
- zend_execute_ex
- execute_ex(zend_vm_execute.h)
- zend_vm_stack_free_call_frame
后续部分:gc/php modules and zend extensions/grammar/ast/thread safety
ref:php-src