当前位置:Gxlcms > PHP教程 > 【php原理】狂言php常量

【php原理】狂言php常量

时间:2021-07-01 10:21:17 帮助过:14人阅读

【php原理】大话php常量

我们先看一个php常量的定义方法

  1. <code style="font-size:14px; line-height:1.3em; border-left-width:4px; border-left-style:solid; border-left-color:rgb(0,136,0); display:block; padding:0.5em; color:rgb(0,0,0)">define(<span class="string" style="color:rgb(136,0,0)">'PRICE'</span>, <span class="number" style="color:rgb(0,136,0)">30</span>);</code>

之前,我一直把define和C中的宏定义理解一致,因此在使用的时候也只是将其当成简单地字符替换。后来研究了PHP内核以后,发现PHP中的常量和宏定义完全不是一回事。

在PHP脚本运行的过程中,zend引擎会维护一个常量列表,对于普通用户来说,可以对这个常量列表进行CRUD操作,api分别为

define():定义一个常量

defined(): 判断一个常量是否存在

constant(): 得到一个常量的值

我们来看下PHP内核中常量的定义

  1. <code style="font-size:14px; line-height:1.3em; border-left-width:4px; border-left-style:solid; border-left-color:rgb(0,136,0); display:block; padding:0.5em; color:rgb(0,0,0)"><span class="keyword" style="font-weight:bold">typedef</span> <span class="keyword" style="font-weight:bold">struct</span> _zend_constant{
  2. zval value;
  3. <span class="keyword" style="font-weight:bold">int</span> flags;
  4. <span class="keyword" style="font-weight:bold">char</span> *name;
  5. uint name_len;
  6. <span class="keyword" style="font-weight:bold">int</span> module_number;} _zend_constant;</code>

其中value为普通的变量结构zval,在此基础上,常量还定义了标记,常量名和模块号三个属性。

1. 标记(flags)

首先看常量的标记属性flag,目前可供选择的几个可能值分别为

用户态(可通过define方法的第三个参数赋值):

1: case sensitive

0: case insensitive

内核态:

CONST_PERSISTANT: persistent

CONST_CT_SUBST: allow compile-time substitution

用户定义的常量的标记默认为case sensitive, 也可通过define函数的第三个参数进行修改。对于内核态标记,CONST_PERSISTANT代表这个常量在内存申请的时候需要持久化。

上图是PHP脚本运行的的生命周期,我们知道多个request共享一次MINIT和MSHUTDOWN过程,而每个request有自己的RINIT和RSHUTDOWN过程,因此在MINIT中初始化的变量会常驻内存当中。这样被标记为CONST_PERSISTANT的常量只会在MSHUTDOWN中才会被析构掉。这也就不难理解,在内核C代码中,一些字符串和数字作为代码的一部分也被定义为PHP内核中的常量,它们通常就会被标记为CONST_PERSISTENT常量。

而CONST_CT_SUBST目前在内核里只有5个(TRUE, FALSE, NULL, ZEND_THREAD_SAFE, ZEND_DEBUG_BUILD),

2.模块号(module_number)

模块号同样分为用户态和内核态,确切的说,模块号就是用来做此区分的。用户定义的常量均为PHP_USER_CONSTANT, 除此以外,还有一些PHP内置的标准常量,例如E_ALL, E_WARNING等。在zend引擎启动以后,zend会进行标准常量的注册工作(zend_register_standard_constants()),一般来说,这些标准常量都被标记为持久化常量,即CONST_PERSISTENT

3. define()函数

define是PHP的内置接口,用户会通过define来定义常量,其实该方法过程如下

4. 魔术常量

PHP中还提供了一种魔术常量,他们的值是随着外部环境的变化而变化的,例如

__LINE__ 当前文件的行号

__FILE__ 文件的完整路径

这些魔术常量不是真正的常量(_zend_constants),PHP内核在此法解析的时候就会将其替换掉。

最后附上define的源码(在Zend/zend_builtin_functions.c中):

  1. <code style="font-size:14px; line-height:1.3em; border-left-width:4px; border-left-style:solid; border-left-color:rgb(0,136,0); display:block; padding:0.5em; color:rgb(0,0,0)"><span class="comment" style="color:rgb(136,136,136)">/* {{{ proto bool define(string constant_name, mixed value, boolean case_insensitive=false) Define a new constant */</span>ZEND_FUNCTION(define){
  2. <span class="keyword" style="font-weight:bold">char</span> *name;
  3. <span class="keyword" style="font-weight:bold">int</span> name_len;
  4. zval *val;
  5. zval *val_free = NULL;
  6. zend_bool non_cs = <span class="number" style="color:rgb(0,136,0)">0</span>;
  7. <span class="keyword" style="font-weight:bold">int</span> case_sensitive = CONST_CS;
  8. zend_constant c;
  9. <span class="keyword" style="font-weight:bold">if</span> (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, <span class="string" style="color:rgb(136,0,0)">"sz|b"</span>, &name, &name_len, &val, &non_cs) == FAILURE) {
  10. <span class="keyword" style="font-weight:bold">return</span>;
  11. }
  12. <span class="keyword" style="font-weight:bold">if</span>(non_cs) {
  13. case_sensitive = <span class="number" style="color:rgb(0,136,0)">0</span>;
  14. }
  15. <span class="comment" style="color:rgb(136,136,136)">/* class constant, check if there is name and make sure class is valid & exists */</span>
  16. <span class="keyword" style="font-weight:bold">if</span> (zend_memnstr(name, <span class="string" style="color:rgb(136,0,0)">"::"</span>, <span class="keyword" style="font-weight:bold">sizeof</span>(<span class="string" style="color:rgb(136,0,0)">"::"</span>) - <span class="number" style="color:rgb(0,136,0)">1</span>, name + name_len)) {
  17. zend_error(E_WARNING, <span class="string" style="color:rgb(136,0,0)">"Class constants cannot be defined or redefined"</span>);
  18. RETURN_FALSE;
  19. }repeat:
  20. <span class="keyword" style="font-weight:bold">switch</span> (Z_TYPE_P(val)) {
  21. <span class="keyword" style="font-weight:bold">case</span> IS_LONG:
  22. <span class="keyword" style="font-weight:bold">case</span> IS_DOUBLE:
  23. <span class="keyword" style="font-weight:bold">case</span> IS_STRING:
  24. <span class="keyword" style="font-weight:bold">case</span> IS_BOOL:
  25. <span class="keyword" style="font-weight:bold">case</span> IS_RESOURCE:
  26. <span class="keyword" style="font-weight:bold">case</span> IS_NULL:
  27. <span class="keyword" style="font-weight:bold">break</span>;
  28. <span class="keyword" style="font-weight:bold">case</span> IS_OBJECT:
  29. <span class="keyword" style="font-weight:bold">if</span> (!val_free) {
  30. <span class="keyword" style="font-weight:bold">if</span> (Z_OBJ_HT_P(val)->get) {
  31. val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);
  32. <span class="keyword" style="font-weight:bold">goto</span> repeat;
  33. } <span class="keyword" style="font-weight:bold">else</span> <span class="keyword" style="font-weight:bold">if</span> (Z_OBJ_HT_P(val)->cast_object) {
  34. ALLOC_INIT_ZVAL(val_free);
  35. <span class="keyword" style="font-weight:bold">if</span> (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS) {
  36. val = val_free;
  37. <span class="keyword" style="font-weight:bold">break</span>;
  38. }
  39. }
  40. }
  41. <span class="comment" style="color:rgb(136,136,136)">/* no break */</span>
  42. <span class="keyword" style="font-weight:bold">default</span>:
  43. zend_error(E_WARNING,<span class="string" style="color:rgb(136,0,0)">"Constants may only evaluate to scalar values"</span>);
  44. <span class="keyword" style="font-weight:bold">if</span> (val_free) {
  45. zval_ptr_dtor(&val_free);
  46. }
  47. RETURN_FALSE;
  48. }
  49. c.value = *val;
  50. zval_copy_ctor(&c.value);
  51. <span class="keyword" style="font-weight:bold">if</span> (val_free) {
  52. zval_ptr_dtor(&val_free);
  53. }
  54. c.flags = case_sensitive; <span class="comment" style="color:rgb(136,136,136)">/* non persistent */</span>
  55. c.name = IS_INTERNED(name) ? name : zend_strndup(name, name_len);
  56. <span class="keyword" style="font-weight:bold">if</span>(c.name == NULL) {
  57. RETURN_FALSE;
  58. }
  59. c.name_len = name_len+<span class="number" style="color:rgb(0,136,0)">1</span>;
  60. c.module_number = PHP_USER_CONSTANT;
  61. <span class="keyword" style="font-weight:bold">if</span> (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {
  62. RETURN_TRUE;
  63. } <span class="keyword" style="font-weight:bold">else</span> {
  64. RETURN_FALSE;
  65. }}<span class="comment" style="color:rgb(136,136,136)">/* }}} */</span></code>

人气教程排行