加入收藏 | 设为首页 | 会员中心 | 我要投稿 开发网_开封站长网 (http://www.0378zz.com/)- 科技、AI行业应用、媒体智能、低代码、办公协同!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP 管理全局的技巧

发布时间:2022-07-21 13:09:44 所属栏目:PHP教程 来源:互联网
导读:管理全局状态 在命令式语言中总是需要一些全局空间。在编程 PHP 或扩展时,我们将明确区分我们所称的请求绑定全局变量和真正的全局变量。 真正的全局变量是跨请求保留的信息片段。这些信息通常是只读的。如果您需要写入这样的全局变量作为请求处理的一部分,
  管理全局状态
  在命令式语言中总是需要一些全局空间。在编程 PHP 或扩展时,我们将明确区分我们所称的请求绑定全局变量和真正的全局变量。
 
  真正的全局变量是跨请求保留的信息片段。这些信息通常是只读的。如果您需要写入这样的全局变量作为请求处理的一部分,那么 PHP 无法帮助您。如果您使用 线程作为多处理模型, 您需要自己执行内存锁。如果你使用 进程作为多处理模型, 您需要使用自己的IPC(进程间通信)。但是,在PHP扩展编程中不应该出现这种情况。
 
  管理请求全局变量
  下面是一个使用请求全局的简单扩展例子:
 
 
 
  /* 真正的 C 全局 */
 
  static zend_long rnd = 0;
 
   
 
  static void pib_rnd_init(void)
 
  {
 
      /* 在 0 到 100 之间随机一个数字 */
 
      php_random_int(0, 100, &rnd, 0);
 
  }
 
   
 
  PHP_RINIT_FUNCTION(pib)
 
  {
 
      pib_rnd_init();
 
   
 
      return SUCCESS;
 
  }
 
   
 
  PHP_FUNCTION(pib_guess)
 
  {
 
      zend_long r;
 
   
 
      if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &r) == FAILURE) {
 
          return;
 
      }
 
   
 
      if (r == rnd) {
 
          /* 将数字重置以进行猜测 */
 
          pib_rnd_init();
 
          RETURN_TRUE;
 
      }
 
   
 
  PHP_FUNCTION(pib_reset)
 
  {
 
      if (zend_parse_parameters_none() == FAILURE) {
 
          return;
 
      }
 
   
 
      pib_rnd_init();
 
  }
 
  如你所见,这个扩展在请求开始时挑选一个随机整型数,之后通过pib_guess()可以尝试猜到这个数组。一旦猜到,该数字将重置。如果用户想要手动重置数字,它也可以自己手动调用pib_reset() 去重置数值。
  该随机数作为一个 C 全局变量实现。如果 PHP 在进程中作为多进程模型的一部分使用不再是个问题,如果之后使用线程,这是不行的。
 
  注意
 
  作为提醒,你无需掌握将要使用哪种多进程模型。当你设计扩展时,你必须为这两种模型做好准备。
 
  当使用线程,会针对服务器中的每个线程共享一个 C 全局变量。例如我们上面的例子,网络服务器的每个并行用户将共享同一个数值。一些可能会一开始就重置数值,而其他则尝试去猜测它。简而言之,你清楚地了解了线程的关键问题。
 
  我们必须持久化数据到同一请求,即使运行 PHP 多进程模型会利用线程,也必须让它绑定到当前请求中。
 
  使用 TSRM 宏来保护全局空间
  PHP 设计了可以帮助扩展和内核开发人员处理全局请求的层。该层称为TSRM (线程安全资源管理) ,并且作为一组宏公开,你必须在任何需要访问请求绑定全局(读和写)的时候使用该宏。
 
  在多进程模型使用流程的情况下,在后台,这些宏将解析为类似我们上面显示的代码。如我们所见,如果不适用线程,上面的代码是完全有效的。所以,当使用进程时,这些宏将被扩展为类似的宏。
 
 
  ZEND_BEGIN_MODULE_GLOBALS(pib)
 
      zend_long rnd;
 
  ZEND_END_MODULE_GLOBALS(pib)
 
   
 
  /* 解析为 :
 
  *
 
  * typedef struct _zend_pib_globals {
 
  *    zend_long rnd;
 
  * } zend_pib_globals;
 
  */
 
  然后,创建一个这样的全局变量:
 
 
  ZEND_DECLARE_MODULE_GLOBALS(pib)
 
 
  /* 解析为 zend_pib_globals pib_globals; */
 
  现在,你可以使用全局宏访问器访问数据。这个宏是由框架创建的,它应该在你的 php_pib.h 头文件定义。这看起来是这样的:
 
 
  #ifdef ZTS
 
  #define PIB_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(pib, v)
 
  #else
 
  #define PIB_G(v) (pib_globals.v)
 
  #endif
 
  如你所见,如果没有启用 ZTS 模式,即编译非线程安全的 PHP 和扩展(我们称之为 NTS模式:非线程安全),宏只是解析到结构中声明的数据。因此,有以下变化:
 
      php_random_int(0, 100, &PIB_G(rnd), 0);
 
  }
 
   
 
  PHP_FUNCTION(pib_guess)
 
  {
 
      zend_long r;
 
   
 
      if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &r) == FAILURE) {
 
          return;
 
      }
 
   
 
      if (r == PIB_G(rnd)) {
 
          pib_rnd_init();
 
          RETURN_TRUE;
 
      }
 
   
 
      if (r < PIB_G(rnd)) {
 
          RETURN_STRING("more");
 
      }
 
   
 
      RETURN_STRING("less");
 
  }
 
  注意
 
  当使用一个进程模型,TSRM 宏解析为对 C 全局变量的访问。
 
  当使用线程时,即当你编译 ZTS PHP,事情变得更复杂。然后,我们看到的所有宏都解析为一些完全不同的东西,在这里很难解释。基本上,当使用 ZTS 编译时,TSRM 使用 TLS(线程本地存储)执行了一项艰难的工作。
 
  注意
 
  简而言之,当在 ZTS 编译时,全局变量将绑定到当前线程。而在 NTS 编译时,全局变量将绑定到当前进程上。TSRM 宏处理这项艰难的工作。你可能对运作方式感兴趣,浏览 PHP 源代码的/TSRM 目录了解更多关于 PHP 线程安全。
 
  在扩展中使用全局钩子
  有时,可能需要将全局变量初始化为一些默认值,通常为零。引擎帮助下的TSRM系统提供了一个钩子来为您的全局变量提供默认值,我们称之为GINIT。
 
  注意
 
  关于 PHP 挂钩的完整信息,请参考 PHP 生命周期章节。
 
 
 
  PHP_GSHUTDOWN_FUNCTION(pib)
 
  { }
 
   
 
  PHP_GINIT_FUNCTION(pib)
 
  {
 
      pib_globals->rnd = 0;
 
  }
 
   
 
  zend_module_entry pib_module_entry = {
 
      STANDARD_MODULE_HEADER,
 
      "pib",
 
      NULL,
 
      NULL,
 
      "0.1",
 
      PHP_MODULE_GLOBALS(pib),
 
      PHP_GINIT(pib),
 
      PHP_GSHUTDOWN(pib),
 
      NULL, /* PRSHUTDOWN() */
 
      STANDARD_MODULE_PROPERTIES_EX
 
  };

(编辑:开发网_开封站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读