PHP 코드 아키텍처
PHP의 모든 부분은 TSRM이라는 레이어에 있습니다. TSRM 레이어는 스레드 보안 관리를 담당합니다. 맨 아래 SAPI는 명령줄 sapi와 같은 외부 서비스를 제공하는 인터페이스입니다. -fpm은 fastcgi의 sapi이고 apache의 모듈 모드도 sapi입니다.
PHP 커널 및 Zend 엔진은 요청 관리/네트워크 및 파일 작업을 담당하고 Zend 커널은 컴파일 및 작업을 담당합니다. 실행/메모리 및 리소스 할당
이 중 확장 계층이 있습니다. PHP의 대부분의 외부 인터페이스는 확장 계층을 통해 제공됩니다. 예를 들어 표준 및 문자열과 같은 언어 기반도 확장된 형태로 제공됩니다.
확장(나중에 모듈이라고 함)을 PHP에 로드하는 방법에는 정적 컴파일과 동적 링크의 두 가지가 있습니다. 정적 컴파일을 위해서는 PHP의 구성 스크립트를 다시 생성해야 하며, 이에 대해서는 여기서 설명하지 않습니다. 동적 링크 방법은 그런 다음 .so 파일을 동적으로 로드합니다.
.so 파일을 로드하는 방법에는 두 가지가 있습니다. 하나는 php.ini 파일에 쓰는 것입니다(예: Extension=apc.so). 코드('xxx.so')에서 dl을 사용합니다.
dl($library)
함수는 모듈을 로드하여 내부 기능을 사용할 수 있도록 하는 것입니다.
dl() 함수의 소스 코드는 다음과 같습니다. PHP 소스 코드 루트 디렉터리(약어로 PHP_SRC_HOME), PHP_SRC_HOME/ext/standard/dl.c, 주요 프로세스는 다음과 같습니다.
PHP_FUNCTION(dl)
PHPAPI PHP_FUNCTION(dl) { //... php_dl(filename, MODULE_TEMPORARY, return_value, 0 TSRMLS_CC); //... }
php_dl
PHPAPI void php_dl(char *file, int type, zval *return_value, int start_now TSRMLS_DC) { if (php_load_extension(file, type, start_now TSRMLS_CC) == FAILURE) { //... }
php_load_extension
PHPAPI int php_load_extension(char *filename, int type, int start_now TSRMLS_DC) { //文件名解析相关 //加载动态链接库 handle = DL_LOAD(libpath); //加载错误处理 //获取模块的get_module函数(重点, 模块初始入口) get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module"); //get_module函数获取错误处理 //那个get_module()得到struct zend_module_entry module_entry = get_module(); //... //注册模块(重点, 函数在这里被注册) if ((module_entry = zend_register_module_ex(module_entry TSRMLS_CC)) == NULL) { //错误处理 } //模块启动(重点, PHP_MINIT_FUNCTION) if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry TSRMLS_CC) == FAILURE) { //错误处理 } //模块请求启动(重点, PHP_RINIT_FUNCTION) if ((type == MODULE_TEMPORARY || start_now) && module_entry->request_startup_func) { //错误处理 } return SUCCESS; }
process
get_module function
get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module");
매크로 확장 후 이 코드는 다음과 같습니다.
get_module = (zend_module_entry *(*) (void)) dlsym(handle, "_get_module");
dlsym() 함수가 수행하는 작업은 이 코드를 쉽게 이해할 수 있습니다. 이는 방금 로드된 동적 링크 라이브러리에서
함수 포인터를 얻는 것입니다. 우리가 모듈을 개발하는 이유는 당시 정의된 get_module 함수입니다.매크로 확장 후에는 다음과 같습니다(GNU의 속성과 C++의 extern "C"를 고려하지 않음).
zend_module_entry *get_module(void) { return &sample_module_entry; }
dl()을 넣어서 모듈 개발 중 정의에 연결됩니다. 모듈이 로드되면 사용자 정의된 zend_module_entry가 여기에서 전달되는 것을 볼 수 있습니다. module
module_entry = zend_register_module_ex(module_entry TSRMLS_CC)
위 코드는 php_load_extension 함수에서 추출되었습니다. 우리는 관심 있는 함수 등록을 찾기 위해 계속해서 zend_register_module_ex()를 드릴다운합니다.
if (module->functions && zend_register_functions(NULL, module->functions, NULL, module-> ;type TSRMLS_CC)==FAILURE) {
zend_register_functions 함수를 계속해서 살펴보세요:
ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC) /* {{{ */ { //... //重点 如果没有函数符号表, 取全局函数符号表 if (!target_function_table) { target_function_table = CG(function_table); } //... //重点 循环zend_function_entry[] while (ptr->fname) { //向函数符号表增加函数 if (zend_hash_add(target_function_table, lowercase_name, fname_len+1, &function, sizeof(zend_function), (void**)?_function) == FAILURE) { //错误处理 } //... //准备遍历zend_function_entry[]下一个元素 ptr++; //... } //... return SUCCESS; }
함수 기호 테이블을 얻을 때 CG 매크로가 사용됩니다. :
target_function_table = CG(function_table);
우리는 이를 두 가지 상황으로 나눕니다. 이 매크로를 잠금 해제합니다:
//非线程安全 compiler_globals.function_table //线程安全 (((zend_compiler_globals *) (*((void ***) tsrm_ls))[ compiler_globals_id - 1])-> function_table)
결국 그들이 얻는 것은 zend_compiler_globals에 있는 전역
struct structfunction_table 요소인 HashTable입니다.
다음 루프는 모듈을 개발할 때 zend_function_entry에 넣으면 이해하기 쉽습니다. 함수 탐색이 HashTable에 추가되어 괜찮습니다. 모듈 시작/모듈 요청 시작
이 두 부분은 이해하기 쉽습니다. 모듈 개발에서 각각 PHP_MINIT_FUNCTION() 및 PHP_RINIT_FUNCTION()에 해당
위 내용은 PHP 모듈 개발 관련 지식 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!