PHP中define常量的实现

来源:互联网 发布:乐乎公寓的房子怎么样 编辑:程序博客网 时间:2024/05/18 02:27
在PHP中,常量的名字是一个简单的标识符,执行周期中不能改变,并且默认情况下是大小写敏感的。通常常量总是大写的。

注:define中的第三个参数可以设置是否常量名大小写敏感


一、常量的内部结构

[cpp] view plaincopy
  1. typedef struct _zend_constant {  
  2.     zval value; /* zval结构,PHP内部变量的存储结构 */  
  3.     int flags;  /* 常量的标记如 CONST_PERSISTENT | CONST_CS */  
  4.     char *name; /* 常量名称 */  
  5.     uint name_len;  /* 常量名称字符长度 */  
  6.     int module_number;  /* 模块号 */  
  7. } zend_constant;  

二、PHP中定义常量

[php] view plaincopy
  1. <?php  
  2. define('DATABASE''MYSQL');  
  3. define('DATABASE_USER''ROOT');  
  4. define('DATABASE_PASSWORD''PASSWORD');  

三、分析opcode

# php -dvld.active=1 index.php
打印出opchode,如下图


注,查看opcode扩展VLD安装可以阅读 《通过VLD扩展分析PHP opcode》

这里介绍出现的了三条指令,SEND_VAL、DO_FCALL、RETURN
SEND_VAL:传递参数的固定值,操作码65
RETURN:从函数中返回结果,操作码62
DO_FCALL:调用函数,操作码60

更多指令说明:http://php.net/manual/en/internals2.opcodes.list.php


四、通过ZEND VM执行opcode

[cpp] view plaincopy
  1. void zif_define(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used )  
  2.   
  3. ZEND_FUNCTION(define)  
  4. {  
  5.     char *name;  
  6.     int name_len;  
  7.     zval *val;  
  8.     zval *val_free = NULL;  
  9.     zend_bool non_cs = 0;//接收第三个参数,是否大小写敏感,默认不敏感  
  10.     int case_sensitive = CONST_CS;  
  11.     zend_constant c;    //PHP中常量对应的结构体变量  
  12.   
  13.     /* 
  14.      * sz|b function define(string, zval [, boolean]) 
  15.      * 这个参数表示定义接收的参数,s为字符串,z为zval,b为boolean 
  16.      * */  
  17.     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {  
  18.         return;  
  19.     }  
  20.   
  21.     if(non_cs) {  
  22.         case_sensitive = 0;  
  23.     }  
  24.   
  25.     /* class constant, check if there is name and make sure class is valid & exists */  
  26.     if (zend_memnstr(name, "::"sizeof("::") - 1, name + name_len)) {  
  27.         zend_error(E_WARNING, "Class constants cannot be defined or redefined");  
  28.         RETURN_FALSE;  
  29.     }  
  30.   
  31. repeat:  
  32.     switch (Z_TYPE_P(val)) {  
  33.         case IS_LONG:  
  34.         case IS_DOUBLE:  
  35.         case IS_STRING:  
  36.         case IS_BOOL:  
  37.         case IS_RESOURCE:  
  38.         case IS_NULL:  
  39.             break;  
  40.         //上面,允许integer, float,string 或者 boolean和 null  
  41.         case IS_OBJECT:  
  42.             /* 如果传入的是对象, 通过判断是否定义__tostring()魔术方法,重新设置val值 
  43.              * 可以看出,define已经接受对象作为参数,前提条件是定义了__tostring(),并且返回的值也是integer, float,string 或者 boolean和 null 
  44.              * 此时,这里的版本是php5.3.8 
  45.              * */  
  46.             if (!val_free) {  
  47.                 if (Z_OBJ_HT_P(val)->get) {  
  48.                     val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);  
  49.                     goto repeat;  
  50.                 } else if (Z_OBJ_HT_P(val)->cast_object) {  
  51.                     ALLOC_INIT_ZVAL(val_free);  
  52.                     if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS) {  
  53.                         val = val_free;  
  54.                         break;  
  55.                     }  
  56.                 }  
  57.             }  
  58.             /* no break */  
  59.         default:  
  60.             //其他类型则提示错误  
  61.             zend_error(E_WARNING,"Constants may only evaluate to scalar values");  
  62.             if (val_free) {  
  63.                 zval_ptr_dtor(&val_free);  
  64.             }  
  65.             RETURN_FALSE;  
  66.     }  
  67.       
  68.     c.value = *val;  
  69.     zval_copy_ctor(&c.value);  
  70.     if (val_free) {  
  71.         zval_ptr_dtor(&val_free);  
  72.     }  
  73.     c.flags = case_sensitive; /* non persistent */  
  74.     c.name = zend_strndup(name, name_len);  
  75.     c.name_len = name_len+1;  
  76.     c.module_number = PHP_USER_CONSTANT;  
  77.     if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {  
  78.         RETURN_TRUE;  
  79.     } else {  
  80.         RETURN_FALSE;  
  81.     }  
  82. }  
0 0
原创粉丝点击