在應用中經常使用define來定義一些常用的參數資訊,來增加程式的可讀性和可靠性。
在PHP中,常量的名字是一個簡單的標識符,執行循環中不能改變,並且預設情況下是大小寫敏感的。通常常量總是大寫的。
註:define中的第三個參數可以設定是否常量名大小寫敏感
一、常量的內部結構
typedef struct _zend_constant { zval value; /* zval結構,PHP內部變數的儲存結構 */ int flags; /* 常量的標記如 CONST_PERSISTENT | CONST_CS */ char *name; /* 常量名稱 */ uint name_len; /* 常量名稱字元長度 */ int module_number; /* 模組號 */} zend_constant;
二、PHP中定義常量
<?phpdefine('DATABASE', 'MYSQL');define('DATABASE_USER', 'ROOT');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
void zif_define(int ht, zval *return_value, zval **return_value_ptr, zval *this_ptr, int return_value_used )ZEND_FUNCTION(define){char *name;int name_len;zval *val;zval *val_free = NULL;zend_bool non_cs = 0;//接收第三個參數,是否大小寫敏感,預設不敏感int case_sensitive = CONST_CS;zend_constant c;//PHP中常量對應的結構體變數/* * sz|b function define(string, zval [, boolean]) * 這個參數表示定義接收的參數,s為字串,z為zval,b為boolean * */if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {return;}if(non_cs) {case_sensitive = 0;}/* class constant, check if there is name and make sure class is valid & exists */if (zend_memnstr(name, "::", sizeof("::") - 1, name + name_len)) {zend_error(E_WARNING, "Class constants cannot be defined or redefined");RETURN_FALSE;}repeat:switch (Z_TYPE_P(val)) {case IS_LONG:case IS_DOUBLE:case IS_STRING:case IS_BOOL:case IS_RESOURCE:case IS_NULL:break;//上面,允許integer, float,string 或者 boolean和 nullcase IS_OBJECT:/* 如果傳入的是對象, 通過判斷是否定義__tostring()魔術方法,重新設定val值 * 可以看出,define已經接受對象作為參數,前提條件是定義了__tostring(),並且返回的值也是integer, float,string 或者 boolean和 null * 此時,這裡的版本是php5.3.8 * */if (!val_free) {if (Z_OBJ_HT_P(val)->get) {val_free = val = Z_OBJ_HT_P(val)->get(val TSRMLS_CC);goto repeat;} else if (Z_OBJ_HT_P(val)->cast_object) {ALLOC_INIT_ZVAL(val_free);if (Z_OBJ_HT_P(val)->cast_object(val, val_free, IS_STRING TSRMLS_CC) == SUCCESS) {val = val_free;break;}}}/* no break */default://其他類型則提示錯誤zend_error(E_WARNING,"Constants may only evaluate to scalar values");if (val_free) {zval_ptr_dtor(&val_free);}RETURN_FALSE;}c.value = *val;zval_copy_ctor(&c.value);if (val_free) {zval_ptr_dtor(&val_free);}c.flags = case_sensitive; /* non persistent */c.name = zend_strndup(name, name_len);c.name_len = name_len+1;c.module_number = PHP_USER_CONSTANT;if (zend_register_constant(&c TSRMLS_CC) == SUCCESS) {RETURN_TRUE;} else {RETURN_FALSE;}}