色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

PHP內(nèi)核探索 —— 常量的實(shí)現(xiàn)

瀏覽:6日期:2022-09-16 14:31:55

常量,顧名思義是一個(gè)常態(tài)的量值。它與值只綁定一次,它的作用在于有肋于增加程序的可讀性和可靠性。 在PHP中,常量的名字是一個(gè)簡(jiǎn)單值的標(biāo)識(shí)符,在腳本執(zhí)行期間該值不能改變。 和變量一樣,常量默認(rèn)為大小寫敏感,但是按照我們的習(xí)慣常量標(biāo)識(shí)符總是大寫的。 常量名和其它任何 PHP 標(biāo)簽遵循同樣的命名規(guī)則。合法的常量名以字母或下劃線開(kāi)始,后面跟著任何字母,數(shù)字或下劃線。

在設(shè)定以后,常量的值無(wú)法更改常量名不需要開(kāi)頭的美元符號(hào) ($)作用域不影響對(duì)常量的訪問(wèn)常量值只能是字符串或數(shù)字

在這一小節(jié)我們一起看下常量與我們常見(jiàn)的變量有啥區(qū)別,它在執(zhí)行期間的不可改變的特性是如何實(shí)現(xiàn)的以及常量的定義過(guò)程。

首先看下常量與變量的區(qū)別,常量是在變量的zval結(jié)構(gòu)的基礎(chǔ)上添加了一額外的元素。如下所示為PHP中常量的內(nèi)部結(jié)構(gòu)。

常量的內(nèi)部結(jié)構(gòu)

typedef struct _zend_constant { zval value; /* zval結(jié)構(gòu),PHP內(nèi)部變量的存儲(chǔ)結(jié)構(gòu),在第一小節(jié)有說(shuō)明 */ int flags; /* 常量的標(biāo)記如 CONST_PERSISTENT | CONST_CS */ char *name; /* 常量名稱 */ uint name_len; int module_number; /* 模塊號(hào) */} zend_constant;

在Zend/zend_constants.h文件的33行可以看到如上所示的結(jié)構(gòu)定義。 在常量的結(jié)構(gòu)中,除了與變量一樣的zval結(jié)構(gòu),它還包括屬于常量的標(biāo)記,常量名以及常量所在的模塊號(hào)。

在了解了常量的存儲(chǔ)結(jié)構(gòu)后,我們來(lái)看PHP常量的定義過(guò)程。一個(gè)例子。

define(’ICULTIVATOR’, ’www.icultivator.com’);

這是一個(gè)很常規(guī)的常量定義過(guò)程,它使用了PHP的內(nèi)置函數(shù)define。常量名為ICULTIVATOR,值為一個(gè)字符串,存放在zval結(jié)構(gòu)中。 從這個(gè)例子出發(fā),我們看下define定義常量的過(guò)程實(shí)現(xiàn)。

define定義常量

define是PHP的內(nèi)置函數(shù),在Zend/zend_builtin_functions.c文件中定義了此函數(shù)的實(shí)現(xiàn)。如下所示為部分源碼:

/* {{{ proto bool define(string constant_name, mixed value, boolean case_insensitive=false) Define a new constant */ZEND_FUNCTION(define){if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, 'sz|b', &name,&name_len, &val, &non_cs) == FAILURE) {return;}... // 類常量定義 此處不做介紹... // 值類型判斷和處理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;}}/* }}} */

上面的代碼已經(jīng)對(duì)對(duì)象和類常量做了簡(jiǎn)化處理, 其實(shí)現(xiàn)基本上是一個(gè)將傳遞的參數(shù)傳遞給新建的zend_constant結(jié)構(gòu),并將這個(gè)結(jié)構(gòu)體注冊(cè)到常量列表中的過(guò)程。 關(guān)于大小寫敏感,函數(shù)的第三個(gè)參數(shù)表示是否大小不敏感,默認(rèn)為false(大小寫敏感)。這個(gè)參數(shù)最后會(huì)賦值給zend_constant結(jié)構(gòu)體的flags字段。其在函數(shù)中實(shí)現(xiàn)代碼如下:

zend_bool non_cs = 0; // 第三個(gè)參數(shù)的臨時(shí)存儲(chǔ)變量int case_sensitive = CONST_CS; // 是否大小寫敏感,默認(rèn)為1if(non_cs) { // 輸入為真,大小寫不敏感 case_sensitive = 0;}c.flags = case_sensitive; // 賦值給結(jié)構(gòu)體字段

從上面的define函數(shù)的實(shí)現(xiàn)來(lái)看,PHP對(duì)于常量的名稱在定義時(shí)其實(shí)是沒(méi)有所謂的限制。如下所示代碼:

define(’^_^’, ’smile’);if (defined(’^_^’)) { echo ’yes’;}else{ echo ’no’;}//$var = ^_^; //語(yǔ)法錯(cuò)誤$var = constant('^_^');

通過(guò)defined函數(shù)測(cè)試表示,‘^_^’這個(gè)常量已經(jīng)定義好,這樣的常量無(wú)法直接調(diào)用, 只能使用constant語(yǔ)句來(lái)使用, 否則在語(yǔ)法解析時(shí)會(huì)顯示錯(cuò)誤。 在上面的代碼中有用到一個(gè)判斷常量是否定義的函數(shù),下面我們看看這個(gè)函數(shù)是如何實(shí)現(xiàn)的。

判斷常量是否設(shè)置

和define一樣, defined的實(shí)現(xiàn)也在Zend/zend_builtin_functions.c文件, 其實(shí)現(xiàn)是一個(gè)讀取參數(shù)變量,調(diào)用 zend_get_constant_ex函數(shù)獲取常量的值來(lái)判斷常量是否存在的過(guò)程。 而zend_get_constant_ex函數(shù)不僅包括了常規(guī)的常規(guī)的常量獲取,還包括類常量的獲取, 最后是通過(guò)zend_get_constant函數(shù)獲取常量的值。在zend_get_constant函數(shù)中,基本上是通過(guò)下面的代碼來(lái)獲取常量的值。

zend_hash_find(EG(zend_constants), name, name_len+1, (void **) &c)

除此之外,只是調(diào)用這個(gè)函數(shù)之前和之后對(duì)name有一些特殊的處理。

常量的初始化

以上通過(guò)define定義的常量的模塊編號(hào)都是PHP_USER_CONSTANT,這表示是用戶定義的常量。 除此之外我們?cè)谄綍r(shí)使用較多的,如在顯示所有級(jí)別錯(cuò)誤報(bào)告時(shí)使用的E_ALL常量就有點(diǎn)不同了。 這里我們以cgi模式為例說(shuō)明標(biāo)準(zhǔn)常量的定義過(guò)程。 整個(gè)調(diào)用順序如下所示:

[php_cgi_startup() -> php_module_startup() -> zend_startup() -> zend_register_standard_constants()]

void zend_register_standard_constants(TSRMLS_D){ ... // 若干常量以REGISTER_MAIN_LONG_CONSTANT設(shè)置, REGISTER_MAIN_LONG_CONSTANT('E_ALL', E_ALL, CONST_PERSISTENT | CONST_CS); ...}

REGISTER_MAIN_LONG_CONSTANT宏展開(kāi)是以zend_register_long_constant實(shí)現(xiàn)。 zend_register_long_constant函數(shù)將常量中值的類型,值,名稱及模塊號(hào)賦值給新的zend_constant。 并調(diào)用zend_register_constant添加到全局的常量列表中。

[php_cgi_startup() -> php_module_startup() -> zend_startup() -> zend_register_standard_constants() -> zend_register_constant]

ZEND_API void zend_register_long_constant(const char *name, uint name_len,long lval, int flags, int module_number TSRMLS_DC){ zend_constant c; c.value.type = IS_LONG; c.value.value.lval = lval; c.flags = flags; c.name = zend_strndup(name, name_len-1); c.name_len = name_len; c.module_number = module_number; zend_register_constant(&c TSRMLS_CC);}

zend_register_constant函數(shù)首先根據(jù)常量中的c->flags判斷是否區(qū)分大小寫, 如果不區(qū)分,則名字統(tǒng)一為小寫,如果包含'',也統(tǒng)一成小寫。否則為定義的名字 然后將調(diào)用下面的語(yǔ)句將當(dāng)前常量添加到EG(zend_constants)。 EG(zend_constants)是一個(gè)HashTable(這在前面的章節(jié)中說(shuō)明), 下面的代碼是將常量添加到這個(gè)HashTable中。

zend_hash_add(EG(zend_constants), name, c->name_len, (void *) c,sizeof(zend_constant), NULL)==FAILURE)

在php_module_startup函數(shù)中,除了zend_startup函數(shù)中有注冊(cè)標(biāo)準(zhǔn)的常量, 它本身體通過(guò)宏REGISTER_MAIN_LONG_CONSTANT等注冊(cè)了一些常量,如:PHP_VERSION,PHP_OS等。

標(biāo)簽: PHP
相關(guān)文章:
主站蜘蛛池模板: 三级网站免费观看 | 国产一级a毛片高清 | 看中国一级毛片 | 欧美日韩亚洲国产精品 | 成人午夜视频一区二区国语 | 欧美日韩色黄大片在线视频 | 两性色午夜视频免费国产 | 亚洲国产综合精品 | 日韩一级欧美一级 | 狠狠色丁香婷婷久久综合考虑 | 久国产精品视频 | 99国产精品久久久久久久成人热 | 亚洲综合影视 | 精品国产欧美精品v | 亚洲一区中文字幕在线 | 韩国一级a毛片 | 欧美一级片在线播放 | 成年人免费软件 | 国产特黄一级一片免费 | 欧美日韩一区在线观看 | 亚洲永久免费 | 99免费在线播放99久久免费 | 国产一区二区三区在线观看免费 | 美女很黄免费 | 毛片免费的 | 美女又爽又黄视频 | 91久久精品青青草原伊人 | 亚洲欧美视频一区二区三区 | 浮力影院网站午夜 | 97青青草原国产免费观看 | 成人久久18免费软件 | 一级一级特黄女人精品毛片 | 男女视频在线观看免费 | 欧美不卡视频在线观看 | 自怕偷自怕亚洲精品 | 日本无卡码一区二区三区 | 免费手机黄色网址 | 亚洲综合久久1区2区3区 | 成年女人午夜免费视频 | 亚洲人成综合在线播放 | 一本一道波多野结衣456 |