php 启动过程 - sapi MINIT 过程

sapi 概念

  • sapi 是 php 的应用编程接口, server 端接收请求通过 sapi 接口层交给 php 处理
  • 不同的 server 端底层实现不同, 相应的数据结构已经方法也有所不同, 但是对于 php 层面来说是一样的, 就是因为 sapi 层的存在
  • sapi 层对不同的 server 端进行了封装, 让 php 在处理时, 采用统一的处理方法, 并不感知底层到底是什么 server 端

sapi 生命周期前的启动过程 (以 apache2 为例)

  • apache 加载 php 模块

    • httpd.conf 配置

      • LoadModule php5_module modules/mod_php5.so
      • php5_module 是模块名称

      • apache 在启动加载模块时会根据模块名查找并加载模块, apache 模块文件必须是 "mod_" 开头的文件, 对于 php 来说, 则是 mod_php5.c

      • apache 的每个模块均为 module 结构体

        • AP_MODULE_DECLARE_DATA module php5_module = {
          STANDARD20_MODULE_STUFF,
          create_php_config, /* create per-directory config structure */
          merge_php_config, /* merge per-directory config structures */
          NULL, /* create per-server config structure */
          NULL, /* merge per-server config structures */
          // 模块指令集合
          php_dir_cmds, /* command apr_table_t */
          // php 模块注册钩子, 服务启动时注册
          php_ap2_register_hook /* register hooks */
          };
        • php_dir_cmds 为模块指令集, 当 apache 接收到指令后, 会遍历每个模块的指令集, 查看哪个模块能处理该指令, 进而调用相应处理函数

        • php_ap2_register_hook 为模块注册钩子, 当 apache 启动加载模块时调用

          • void php_ap2_register_hook(apr_pool_t *p)
            {
            ap_hook_pre_config(php_pre_config, NULL, NULL, APR_HOOK_MIDDLE);
            // apache2 的注册钩子
            ap_hook_post_config(php_apache_server_startup, NULL, NULL, APR_HOOK_MIDDLE);
            // apache2 处理请求时的钩子
            ap_hook_handler(php_handler, NULL, NULL, APR_HOOK_MIDDLE);
            ap_hook_child_init(php_apache_child_init, NULL, NULL, APR_HOOK_MIDDLE);
            }
          • 定义位置在 sapi/apache2handler/sapi_apache2.c

          • ap_hook_pre_config, ap_hook_post_config, ap_hook_child_init 这三个钩子均在 apache 启动时调用, ap_hook_handler 钩子在每次处理请求时均会调用, 在 ap_hook_post_config 中启动 php

          • 调用 php_apache_server_startup

            • static int php_apache_server_startup(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
              {
              // 省略
              if (apache2_php_ini_path_override) {
              apache2_sapi_module.php_ini_path_override = apache2_php_ini_path_override;
              }
              #ifdef ZTS
              // 启动线程安全资源管理
              tsrm_startup(1, 1, 0, NULL);
              #endif
              // sapi 启动
              sapi_startup(&apache2_sapi_module);
              //
              apache2_sapi_module.startup(&apache2_sapi_module);
              apr_pool_cleanup_register(pconf, NULL, php_apache_server_shutdown, apr_pool_cleanup_null);
              php_apache_add_version(pconf); return OK;
              }
  • sapi 启动

    • sapi 模块结构体

      static sapi_module_struct apache2_sapi_module = {
      "apache2handler",
      "Apache 2.0 Handler", php_apache2_startup, /* startup */
      php_module_shutdown_wrapper, /* shutdown */ NULL, /* activate */
      NULL, /* deactivate */ php_apache_sapi_ub_write, /* unbuffered write */
      php_apache_sapi_flush, /* flush */
      php_apache_sapi_get_stat, /* get uid */
      php_apache_sapi_getenv, /* getenv */ php_error, /* error handler */ php_apache_sapi_header_handler, /* header handler */
      php_apache_sapi_send_headers, /* send headers handler */
      NULL, /* send header handler */ php_apache_sapi_read_post, /* read POST data */
      php_apache_sapi_read_cookies, /* read Cookies */ php_apache_sapi_register_variables,
      php_apache_sapi_log_message, /* Log message */
      php_apache_sapi_get_request_time, /* Request Time */
      NULL, /* Child Terminate */ STANDARD_SAPI_MODULE_PROPERTIES
      };
    • 调用 tsrm_startup (启动线程安全资源管理, 此处不做进一步展开, 在线程安全时单独展开)

    • 调用 sapi_startup (main/SAPI.c)

      SAPI_API void sapi_startup(sapi_module_struct *sf)
      {
      #ifdef ZEND_SIGNALS
      zend_signal_startup();
      #endif sf->ini_entries = NULL;
      sapi_module = *sf; #ifdef ZTS
      ts_allocate_id(&sapi_globals_id, sizeof(sapi_globals_struct), (ts_allocate_ctor) sapi_globals_ctor, (ts_allocate_dtor) sapi_globals_dtor);
      # ifdef PHP_WIN32
      _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
      # endif
      #else
      sapi_globals_ctor(&sapi_globals);
      #endif virtual_cwd_startup(); /* Could use shutdown to free the main cwd but it would just slow it down for CGI */ #ifdef PHP_WIN32
      tsrm_win32_startup();
      #endif reentrancy_startup();
      }
      • zend_signal_startup: 信号系统

      • sapi_globals_ctor: 创建 sapi 全局结构

        • static void sapi_globals_ctor(sapi_globals_struct *sapi_globals TSRMLS_DC)
          {
          memset(sapi_globals, 0, sizeof(*sapi_globals));
          zend_hash_init_ex(&sapi_globals->known_post_content_types, 5, NULL, NULL, 1, 0);
          php_setup_sapi_content_types(TSRMLS_C);
          }
        • typedef struct _sapi_globals_struct {
          // server 环境上下文
          void *server_context;
          // 请求信息
          sapi_request_info request_info;
          // 头信息
          sapi_headers_struct sapi_headers;
          // post 字节数
          int read_post_bytes;
          // 是否发送头
          unsigned char headers_sent;
          struct stat global_stat;
          // 默认 mime 类型
          char *default_mimetype;
          // 默认字符集
          char *default_charset;
          // 上传文件
          HashTable *rfc1867_uploaded_files;
          // post 请求最大大小
          long post_max_size;
          int options;
          // sapi 是否已启动
          zend_bool sapi_started;
          // 请求时间
          double global_request_time;
          // 已知的 post 的 content_type
          HashTable known_post_content_types;
          zval *callback_func;
          zend_fcall_info_cache fci_cache;
          zend_bool callback_run;
          } sapi_globals_struct;
        • 调用 php_setup_sapi_contents_types, 设置 post 请求相关的参数和处理方法

          int php_setup_sapi_content_types(TSRMLS_D)
          {
          sapi_register_post_entries(php_post_entries TSRMLS_CC); return SUCCESS;
          }
          static sapi_post_entry php_post_entries[] = {
          { DEFAULT_POST_CONTENT_TYPE, sizeof(DEFAULT_POST_CONTENT_TYPE)-1, sapi_read_standard_form_data, php_std_post_handler },
          { MULTIPART_CONTENT_TYPE, sizeof(MULTIPART_CONTENT_TYPE)-1, NULL, rfc1867_post_handler },
          { NULL, 0, NULL, NULL }
          };
          struct _sapi_post_entry {
          char *content_type;
          uint content_type_len;
          void (*post_reader)(TSRMLS_D);
          void (*post_handler)(char *content_type_dup, void *arg TSRMLS_DC);
          };
          • 调用 sapi_register_post_entries

            • SAPI_API int sapi_register_post_entries(sapi_post_entry *post_entries TSRMLS_DC)
              {
              sapi_post_entry *p=post_entries; while (p->content_type) {
              if (sapi_register_post_entry(p TSRMLS_CC) == FAILURE) {
              return FAILURE;
              }
              p++;
              }
              return SUCCESS;
              }
            • SAPI_API int sapi_register_post_entry(sapi_post_entry *post_entry TSRMLS_DC)
              {
              // 若 sapi 已启动并且正在执行当中, 不允许注册 post 结构体
              if (SG(sapi_started) && EG(in_execution)) {
              return FAILURE;
              }
              return zend_hash_add(&SG(known_post_content_types),
              post_entry->content_type, post_entry->content_type_len+1,
              (void *) post_entry, sizeof(sapi_post_entry), NULL);
              }
    • 调用 apache2_sapi_module.startup

      static int php_apache2_startup(sapi_module_struct *sapi_module)
      {
      if (php_module_startup(sapi_module, &php_apache_module, 1)==FAILURE) {
      return FAILURE;
      }
      return SUCCESS;
      }
      • php_apache_module 参数是 zend 引擎封装的模块结构

        • zend_module_entry php_apache_module = {
          STANDARD_MODULE_HEADER,
          "apache2handler",
          apache_functions,
          PHP_MINIT(apache), // 扩展为 zm_startup_##module
          PHP_MSHUTDOWN(apache), // 扩展为 zm_shutdown_##module
          NULL,
          NULL,
          PHP_MINFO(apache), // 扩展为 zm_info_##module
          NULL,
          STANDARD_MODULE_PROPERTIES
          };
        • struct _zend_module_entry {
          unsigned short size;
          unsigned int zend_api;
          unsigned char zend_debug;
          unsigned char zts;
          const struct _zend_ini_entry *ini_entry;
          const struct _zend_module_dep *deps;
          // 模块名称
          const char *name;
          const 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);
          // 版本
          const 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;
          const char *build_id;
          };
      • 调用 php_module_startup (main/main.c)

        • int php_module_startup(sapi_module_struct *sf, zend_module_entry *additional_modules, uint num_additional_modules)
          {
          zend_utility_functions zuf;
          zend_utility_values zuv;
          int retval = SUCCESS, module_number=0; /* for REGISTER_INI_ENTRIES() */
          char *php_os;
          zend_module_entry *module; // 省略 ... module_shutdown = 0;
          module_startup = 1;
          // 初始化空请求
          sapi_initialize_empty_request(TSRMLS_C);
          // sapi 激活
          sapi_activate(TSRMLS_C); if (module_initialized) {
          return SUCCESS;
          } sapi_module = *sf;
          // php 输出功能启动
          php_output_startup();
          // 设置 zend 引擎使用的函数
          zuf.error_function = php_error_cb;
          zuf.printf_function = php_printf;
          zuf.write_function = php_output_wrapper;
          zuf.fopen_function = php_fopen_wrapper_for_zend;
          zuf.message_handler = php_message_handler_for_zend;
          zuf.block_interruptions = sapi_module.block_interruptions;
          zuf.unblock_interruptions = sapi_module.unblock_interruptions;
          zuf.get_configuration_directive = php_get_configuration_directive_for_zend;
          zuf.ticks_function = php_run_ticks;
          zuf.on_timeout = php_on_timeout;
          zuf.stream_open_function = php_stream_open_for_zend;
          zuf.vspprintf_function = vspprintf;
          zuf.getenv_function = sapi_getenv;
          zuf.resolve_path_function = php_resolve_path_for_zend;
          // zend 引擎启动
          zend_startup(&zuf, NULL TSRMLS_CC); // 省略 ... // 创建垃圾回收机制全局结构体
          gc_globals_ctor(TSRMLS_C); // 省略 ... // 设置全局结构体的一些值
          EG(bailout) = NULL;
          EG(error_reporting) = E_ALL & ~E_NOTICE;
          EG(active_symbol_table) = NULL;
          PG(header_is_being_sent) = 0;
          SG(request_info).headers_only = 0;
          SG(request_info).argv0 = NULL;
          SG(request_info).argc=0;
          SG(request_info).argv=(char **)NULL;
          PG(connection_status) = PHP_CONNECTION_NORMAL;
          PG(during_request_startup) = 0;
          PG(last_error_message) = NULL;
          PG(last_error_file) = NULL;
          PG(last_error_lineno) = 0;
          EG(error_handling) = EH_NORMAL;
          EG(exception_class) = NULL;
          PG(disable_functions) = NULL;
          PG(disable_classes) = NULL;
          EG(exception) = NULL;
          EG(objects_store).object_buckets = NULL; // 省略 ... // 注册一些常量
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_VERSION", PHP_VERSION, sizeof(PHP_VERSION)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_MAJOR_VERSION", PHP_MAJOR_VERSION, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_MINOR_VERSION", PHP_MINOR_VERSION, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_RELEASE_VERSION", PHP_RELEASE_VERSION, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_EXTRA_VERSION", PHP_EXTRA_VERSION, sizeof(PHP_EXTRA_VERSION) - 1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_VERSION_ID", PHP_VERSION_ID, CONST_PERSISTENT | CONST_CS);
          #ifdef ZTS
          REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 1, CONST_PERSISTENT | CONST_CS);
          #else
          REGISTER_MAIN_LONG_CONSTANT("PHP_ZTS", 0, CONST_PERSISTENT | CONST_CS);
          #endif
          REGISTER_MAIN_LONG_CONSTANT("PHP_DEBUG", PHP_DEBUG, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_OS", php_os, strlen(php_os), CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_SAPI", sapi_module.name, strlen(sapi_module.name), CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("DEFAULT_INCLUDE_PATH", PHP_INCLUDE_PATH, sizeof(PHP_INCLUDE_PATH)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PEAR_INSTALL_DIR", PEAR_INSTALLDIR, sizeof(PEAR_INSTALLDIR)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PEAR_EXTENSION_DIR", PHP_EXTENSION_DIR, sizeof(PHP_EXTENSION_DIR)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_EXTENSION_DIR", PHP_EXTENSION_DIR, sizeof(PHP_EXTENSION_DIR)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_PREFIX", PHP_PREFIX, sizeof(PHP_PREFIX)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINDIR", PHP_BINDIR, sizeof(PHP_BINDIR)-1, CONST_PERSISTENT | CONST_CS);
          #ifndef PHP_WIN32
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_MANDIR", PHP_MANDIR, sizeof(PHP_MANDIR)-1, CONST_PERSISTENT | CONST_CS);
          #endif
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_LIBDIR", PHP_LIBDIR, sizeof(PHP_LIBDIR)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_DATADIR", PHP_DATADIR, sizeof(PHP_DATADIR)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_SYSCONFDIR", PHP_SYSCONFDIR, sizeof(PHP_SYSCONFDIR)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_LOCALSTATEDIR", PHP_LOCALSTATEDIR, sizeof(PHP_LOCALSTATEDIR)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_PATH", PHP_CONFIG_FILE_PATH, strlen(PHP_CONFIG_FILE_PATH), CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_CONFIG_FILE_SCAN_DIR", PHP_CONFIG_FILE_SCAN_DIR, sizeof(PHP_CONFIG_FILE_SCAN_DIR)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_SHLIB_SUFFIX", PHP_SHLIB_SUFFIX, sizeof(PHP_SHLIB_SUFFIX)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_EOL", PHP_EOL, sizeof(PHP_EOL)-1, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_MAXPATHLEN", MAXPATHLEN, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_INT_MAX", LONG_MAX, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_INT_SIZE", sizeof(long), CONST_PERSISTENT | CONST_CS); #ifdef PHP_WIN32
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_MAJOR", EG(windows_version_info).dwMajorVersion, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_MINOR", EG(windows_version_info).dwMinorVersion, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_BUILD", EG(windows_version_info).dwBuildNumber, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_PLATFORM", EG(windows_version_info).dwPlatformId, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SP_MAJOR", EG(windows_version_info).wServicePackMajor, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SP_MINOR", EG(windows_version_info).wServicePackMinor, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_SUITEMASK", EG(windows_version_info).wSuiteMask, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_VERSION_PRODUCTTYPE", EG(windows_version_info).wProductType, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_DOMAIN_CONTROLLER", VER_NT_DOMAIN_CONTROLLER, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_SERVER", VER_NT_SERVER, CONST_PERSISTENT | CONST_CS);
          REGISTER_MAIN_LONG_CONSTANT("PHP_WINDOWS_NT_WORKSTATION", VER_NT_WORKSTATION, CONST_PERSISTENT | CONST_CS);
          #endif
          // php 命令初始化, 主要是设置 php 命令路径
          php_binary_init(TSRMLS_C);
          if (PG(php_binary)) {
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINARY", PG(php_binary), strlen(PG(php_binary)), CONST_PERSISTENT | CONST_CS);
          } else {
          REGISTER_MAIN_STRINGL_CONSTANT("PHP_BINARY", "", 0, CONST_PERSISTENT | CONST_CS);
          }
          // 注册 php 输出功能相关的一些常量
          php_output_register_constants(TSRMLS_C);
          // 注册 php 上传功能相关的一些常量
          php_rfc1867_register_constants(TSRMLS_C); // 读取 php.ini 配置
          if (php_init_config(TSRMLS_C) == FAILURE) {
          return FAILURE;
          } // 将 php.ini 文件读取的配置注册成 ini_entry
          REGISTER_INI_ENTRIES(); // 注册 zend 引擎的 ini_entry
          zend_register_standard_ini_entries(TSRMLS_C); /* Disable realpath cache if an open_basedir is set */
          if (PG(open_basedir) && *PG(open_basedir)) {
          CWDG(realpath_cache_size_limit) = 0;
          } // php 流的初始化
          if (php_init_stream_wrappers(module_number TSRMLS_CC) == FAILURE) {
          php_printf("PHP: Unable to initialize stream url wrappers.\n");
          return FAILURE;
          } zuv.html_errors = 1;
          zuv.import_use_extension = ".php";
          // 注册超全局数组 $_GET, $_POST, $_COOKIE, ...
          php_startup_auto_globals(TSRMLS_C);
          zend_set_utility_values(&zuv);
          // 启动 sapi 的处理请求功能, 设置一些处理函数
          php_startup_sapi_content_types(TSRMLS_C); // 注册 php 内置扩展 (module_registry)
          if (php_register_internal_extensions_func(TSRMLS_C) == FAILURE) {
          php_printf("Unable to start builtin modules\n");
          return FAILURE;
          }
          // 注册附加扩展 (module_registry)
          php_register_extensions_bc(additional_modules, num_additional_modules TSRMLS_CC);
          // 注册 php.ini 文件设置的扩展 (zend_extensions)
          php_ini_register_extensions(TSRMLS_C); // 启动各模块 (module_registry), 调用各模块的 startup 方法
          zend_startup_modules(TSRMLS_C);
          // 启动各扩展 (zend_extentions), 调用各扩展的 startup 方法
          zend_startup_extensions();
          // 统计各模块的启动情况
          zend_collect_module_handlers(TSRMLS_C); /* register additional functions */
          if (sapi_module.additional_functions) {
          if (zend_hash_find(&module_registry, "standard", sizeof("standard"), (void**)&module)==SUCCESS) {
          EG(current_module) = module;
          zend_register_functions(NULL, sapi_module.additional_functions, NULL, MODULE_PERSISTENT TSRMLS_CC);
          EG(current_module) = NULL;
          }
          } // 禁用函数
          php_disable_functions(TSRMLS_C);
          // 禁用类
          php_disable_classes(TSRMLS_C); // 省略 ... // sapi
          sapi_deactivate(TSRMLS_C);
          module_startup = 0;
          // 关闭内存管理
          shutdown_memory_manager(1, 0 TSRMLS_CC);
          zend_interned_strings_snapshot(TSRMLS_C); /* we're done */
          return retval;
          }
        • 初始化 zend 引擎使用的一些函数和值

        • 初始化 sapi_global 的一些值 (通过初始化空请求, sapi 激活)

        • 初始化全局结构体的一些值

        • zend 引擎启动

        • 设置一些常量

        • 加载 php.ini 配置

        • 注册各子模块和扩展

        • 启动各子模块和扩展

        • 禁用函数和类

    • 调用 apr_pool_cleanup_register

sapi 生命周期

  • MINIT

    若不细致区分 sapi 启动前的准备工作与启动过程, 上面的部分均可以看成是 sapi MINIT 过程
    若细致区分, sapi 启动前的准备工作是在注册 php 内置扩展之前的部分; 之后的部分为 MINIT 过程
  • RINIT

  • RSHUTDOWN

  • MSHUTDOWN

对于以上内容的更细致的点, 比如线程资源安全, zend 引擎启动, 全局结构体, php.ini 如何加载配置等等等等, 由于篇幅问题, 不在此赘述, 内容太多消化不了, 会在后续一个一个详细剖析, 本节仅涉及到 sapi 生命周期当中的 MINIT 过程

php 启动过程 - sapi MINIT 过程的更多相关文章

  1. php 启动过程 - sapi MSHUTDOWN 过程

    php 启动过程 - sapi MSHUTDOWN 过程 概述 当服务器关闭时, 会走到 sapi MSHUTDOWN 过程 注册过程 本次内容是在 php 启动过程 - sapi MINIT 过程 ...

  2. php 启动过程 - reqeust RINIT 过程

    php 启动过程 - reqeust RINIT 过程 概述 apache 接收到请求之后, 交给 php 处理 php 模块在接收到请求后, 会对请求进行初始化, 及 RINIT 过程 调用触发 a ...

  3. php 启动过程 - reqeust RSHUTDOWN 过程

    php 启动过程 - reqeust RSHUTDOWN 过程 概述 request RSHUTDOWN 过程在请求结束后调用 调用触发 同 request RINIT 过程一样, 先是用 apach ...

  4. SpringBoot IoC启动流程、初始化过程及Bean生命周期各个阶段的作用

    目录 SpringBoot IoC启动流程.初始化过程及Bean生命周期各个阶段的作用 简述 首先明确IoC容器是啥 准备-SpringApplication的实例化 启动-SpringApplica ...

  5. 第三次作业(1) Visual Studio程序安装过程和练习过程

    Visual Studio程序安装过程和练习过程 第一步 首先要在网上找一个VS2013的安装包,之后我安装在D盘上,C盘上也需要有5.2G空间,勾选相应的选项,才能继续安装. 安装的过程很漫长,接近 ...

  6. Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主 过程导向 vs 结果导向

    Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主    过程导向 vs 结果导向 1. 一个伟大的事业必然是过程导向为主 1 1.1. 过程的执行情况(有明确的执行手册及标准) ...

  7. VScript 函数调用的两种分类:Sub过程和Function过程

    来源:http://soft.zdnet.com.cn/software_zone/2007/0925/523318.shtml 在 VBScript 中,过程被分为两类:Sub 过程和 Functi ...

  8. Oracle数据库体系结构、启动过程、关闭过程

    一.Oracle数据库体系结构体系结构由下面组件组成:1.Oracle服务器(Server):由数据库实例和数据库文件组成,另外在用户建立与服务器的连接时启动服务器进程并分配PGA(程序全局区) (1 ...

  9. iOS开发实践:一个类微博客户端从启动到与用户交互的过程

    本文基于数据字典和数据流图两种工具讲述一个完整微博客户端的实现.数据字典和数据流图都可以用来表达线程的执行流程,同时定义了需要的类,是进一步设计类的基础. 数据字典实际上是一张表,表的第一个字段是程序 ...

随机推荐

  1. 解决springmvc在单纯返回一个字符串对象时所出现的乱码情况(极速版)

    使用springmvc框架开发了这么长时间,之前都是直接返回jsp页面,乱码情况都是通过配置和手动编解码来解决,但是今天突然返回一段单纯的字符串时,发现中文乱码情况解决不了了,下面就给各位分享一下如何 ...

  2. 2015年ACM-ICPC亚洲区域赛合肥站网络预选赛H题——The Next (位运算)

    Let L denote the number of 1s in integer D's binary representation. Given two integers S1 and S2, we ...

  3. Django and Djangorestframework

    NOte Today, another day debuging with my teammates, and I just tried to make complete comprehension ...

  4. canvas的beginPath和closePath分析总结,包括多段弧的情况

    参考博文: Html5 canvas画图教程17:论beginPath的重要性 先看两个例子 例1: <canvas id="myCanvas" width="30 ...

  5. Docker基础入门及示例

    Docker近几年的发展可谓一日千里,特别从是2013年随着一个基于LXC的高级容器引擎开源,到现在,其在linux和windows上都有了很好的支持,并且已经有很多公司将docker用于实际的生产环 ...

  6. ImportError: No module named cv2 解决方法

    ImportError: No module named cv2 解决方法   import cv2时会出现这个问题 解决方法:将openCV安装目录里的python文件夹内的cv2.pyd复制到Py ...

  7. Spring DelegatingFilterProxy

    Spring 里面定义了许多 Filter. 比如 OncePerRequestFilter. 如果我们自定义OncePerRequestFilter, 则可以配置到web.xml中进行一些拦截或日志 ...

  8. rsync+inotify脚本

        #!/bin/bash src=/data/                           # 需要同步的源路径 des=data                             ...

  9. 安装node配置环境变量,解决某组件(如cordova,webpack等)“不是内部命令”问题

    安装cordova之后,控制台输入cordova -v之后,一直提示不是内部命令,查了很久入了很多坑之后,终于配置正确~记录一下~ 1.安装node,我的安装路径为D:\frontend\nodejs ...

  10. windows phone 8.1开发SQlite数据库引用安装

    原文出自:http://www.bcmeng.com/windows-phone-sqlite/ windows phone 8.1开发SQlite数据库引用安装 第一步: 安装SQlite forw ...