ホームページ > バックエンド開発 > PHPチュートリアル > PHP の原則と拡張機能の読み込みプロセスについての深い理解

PHP の原則と拡張機能の読み込みプロセスについての深い理解

WBOY
リリース: 2016-06-20 12:49:50
オリジナル
1325 人が閲覧しました

なぜ xdebug 拡張機能を zend 拡張機能としてロードする必要があるのですか?

zend 拡張機能とは何ですか? 通常の php 拡張機能と zend 拡張機能の違いは何ですか?

拡張機能の読み込みから始めましょう。

PHP は拡張でき、PHP のコア エンジンである Zend Engine も拡張できます。Apache モジュールの作成についても知識がある場合は、次の構造に精通しているでしょう:

struct _zend_extension {        char *name;        char *version;        char *author;        char *URL;        char *copyright;        startup_func_t startup;        shutdown_func_t shutdown;        activate_func_t activate;        deactivate_func_t deactivate;        message_handler_func_t message_handler;        op_array_handler_func_t op_array_handler;        statement_handler_func_t statement_handler;        fcall_begin_handler_func_t fcall_begin_handler;        fcall_end_handler_func_t fcall_end_handler;        op_array_ctor_func_t op_array_ctor;        op_array_dtor_func_t op_array_dtor;        int (*api_no_check)(int api_no);        void *reserved2;        void *reserved3;        void *reserved4;        void *reserved5;        void *reserved6;        void *reserved7;        void *reserved8;        DL_HANDLE handle;        int resource_number;};
ログイン後にコピー

次に、PHP 拡張機能のモジュール エントリを比較してみましょう:

struct _zend_module_entry {          unsigned short size;          unsigned int zend_api;          unsigned char zend_debug;          unsigned char zts;          struct _zend_ini_entry *ini_entry;          struct _zend_module_dep *deps;          char *name;          struct _zend_function_entry *functions;          int (*module_startup_func)(INIT_FUNC_ARGS);          int (*module_shutdown_func)(SHUTDOWN_FUNC_ARGS);          int (*request_startup_func)(INIT_FUNC_ARGS);          int (*request_shutdown_func)(SHUTDOWN_FUNC_ARGS);          void (*info_func)(ZEND_MODULE_INFO_FUNC_ARGS);          char *version;          size_t globals_size;     #ifdef ZTS          ts_rsrc_id* globals_id_ptr;     #else          void* globals_ptr;     #endif          void (*globals_ctor)(void *global TSRMLS_DC);          void (*globals_dtor)(void *global TSRMLS_DC);          int (*post_deactivate_func)(void);          int module_started;          unsigned char type;          void *handle;          int module_number;     };
ログイン後にコピー

上記この構造を前の記事と組み合わせて、C/C++ を使用して PHP を拡張すると、理解が容易になります。

さて、本題に戻ります。Xdebug は Zend Extension モードでロードする必要があるため、要件が必要です。 Zend Extension に基づいていますが、それは何でしょうか?

さて、Xdebug にはプロファイル PHP 関数があることはわかっています。そうです、それは、statement_handler:
ステートメント ハンドラー コールバックは、すべてのステートメントの最後に追加のオペコードを挿入します。この種のコールバックの主な用途の 1 つは、行ごとのプロファイリング、ステッピング デバッガー、またはコード カバレッジ ユーティリティを実装することです。また、Xdebug には

も用意されています。ユーザー スクリプトの関数であるため、PHP 拡張機能の一部の実装も含まれます。また、ZendExt モードでロードされるため、独自の PHPExt 部分のロード プロセスを実装する必要があります。

最後に、ロードします。 PHP Extension のプロセスは次のとおりです (コメントは徐々に追加していきます)。もちろん、知りたくない場合は、私のブログ、風と雪のコーナーに直接メッセージを残していただくこともできます。 🎜> apache/mod_php5.c を例にします

1. mod_php5.c では、Apache モジュール構造が次のように定義されます:

module MODULE_VAR_EXPORT php5_module =     {          STANDARD_MODULE_STUFF,          php_init_handler,           /* initializer */          php_create_dir,             /* per-directory config creator */          php_merge_dir,              /* dir merger */          NULL,                       /* per-server config creator */          NULL,                       /* merge server config */          php_commands,               /* command table */          php_handlers,               /* handlers */          NULL,                       /* filename translation */          NULL,                       /* check_user_id */          NULL,                       /* check auth */          NULL,                       /* check access */          NULL,                       /* type_checker */          NULL,                       /* fixups */          NULL                        /* logger */     #if MODULE_MAGIC_NUMBER >= 19970103          , NULL                      /* header parser */     #endif     #if MODULE_MAGIC_NUMBER >= 19970719          , NULL                      /* child_init */     #endif     #if MODULE_MAGIC_NUMBER >= 19970728          , php_child_exit_handler        /* child_exit */     #endif     #if MODULE_MAGIC_NUMBER >= 19970902          , NULL                      /* post read-request */     #endif     };/* }}} */
ログイン後にコピー

最初に呼び出されるのは php_init_handler、

static void php_init_handler(server_rec *s, pool *p){    register_cleanup(p, NULL, (void (*)(void *))apache_php_module_shutdown_wrapper, (void (*)(void *))php_module_shutdown_for_exec);    if (!apache_php_initialized) {        apache_php_initialized = 1;#ifdef ZTS        tsrm_startup(1, 1, 0, NULL);#endif        sapi_startup(&apache_sapi_module);        php_apache_startup(&apache_sapi_module);    }#if MODULE_MAGIC_NUMBER >= 19980527    {        TSRMLS_FETCH();        if (PG(expose_php)) {            ap_add_version_component("PHP/" PHP_VERSION);        }    }#endif}
ログイン後にコピー

ここで、sapi_startup が呼び出されます。この部分は Apache を初期化するためのものです。 php sapi の

を呼び出し、php_apache_startup を呼び出します:


static int php_apache_startup(sapi_module_struct *sapi_module){    if (php_module_startup(sapi_module, &apache_module_entry, 1) == FAILURE) {        return FAILURE;    } else {        return SUCCESS;    }}
ログイン後にコピー

この時点で、php_module_startup が呼び出されます。これには、以下が含まれます:

/* this will read in php.ini, set up the configuration parameters,       load zend extensions and register php function extensions       to be loaded later */    if (php_init_config(TSRMLS_C) == FAILURE) {        return FAILURE;    }
ログイン後にコピー

は php_init_config を呼び出します。この部分はすべての php.ini と関連する ini ファイルを読み取り、各構成命令を呼び出します:

.... if (sapi_module.ini_entries) {        zend_parse_ini_string(sapi_module.ini_entries, 1, php_config_ini_parser_cb, &extension_lists);    }然后在php_config_ini_parser_cb中:               if (!strcasecmp(Z_STRVAL_P(arg1), "extension")) { /* load function module */                    zval copy;                     copy = *arg2;                    zval_copy_ctor(&copy);                    copy.refcount = 0;                    zend_llist_add_element(&extension_lists.functions, &copy);                } else if (!strcasecmp(Z_STRVAL_P(arg1), ZEND_EXTENSION_TOKEN)) { /* load Zend extension */                    char *extension_name = estrndup(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2));                     zend_llist_add_element(&extension_lists.engine, &extension_name);                } else {                    zend_hash_update(&configuration_hash, Z_STRVAL_P(arg1), Z_STRLEN_P(arg1) + 1, arg2, sizeof(zval), (void **) &entry);                    Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry));                }
ログイン後にコピー

ロードするすべての php 拡張機能と zend 拡張機能をここに記録します。

次に、後で呼び出される php_module_startup に戻ります。

php_ini_register_extensions(TSRMLS_C); >

ここでは、各拡張レコードに対してコールバック関数が呼び出されていることがわかります:
void php_ini_register_extensions(TSRMLS_D){    zend_llist_apply(&extension_lists.engine, php_load_zend_extension_cb TSRMLS_CC);    zend_llist_apply(&extension_lists.functions, php_load_function_extension_cb TSRMLS_CC);     zend_llist_destroy(&extension_lists.engine);    zend_llist_destroy(&extension_lists.functions);}
ログイン後にコピー

最後に、コアの読み込みロジックがあります:
static void php_load_function_extension_cb(void *arg TSRMLS_DC){    zval *extension = (zval *) arg;    zval zval;     php_dl(extension, MODULE_PERSISTENT, &zval, 0 TSRMLS_CC);}
ログイン後にコピー

ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート