常量,顧名思義是一個常態的量值。它與值只綁定一次,它的做用在於有肋於增長程序的可讀性和可靠性。 在PHP中,常量的名字是一個簡單值的標識符,在腳本執行期間該值不能改變。和變量同樣,常量默認爲大小寫敏感,可是按照咱們的習慣常量標識符老是大寫的。 常量名和其它任何 PHP 標籤遵循一樣的命名規則。php
php 7 和以前的版本實現是不同的,下面先說下5.3.5的程序員
php中常量的存儲結構定義是放在Zend/zend_constants.h文件的33行 安全
}zend_constant; php7
定義常量用到的函數是define,這個含糊的實現是在Zend/zend_builtin_functions.c 多線程
char *name;
int name_len;
zval *val;
zval *val_free = NULL;
zend_bool non_cs = 0;
int case_sensitive = CONST_CS;
zend_constant c;函數
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|b", &name, &name_len, &val, &non_cs) == FAILURE) {
return;
}ui
if(non_cs) {
case_sensitive = 0;
}spa
這裏主要的一個函數是zend_parse_parameters,這個函數的功能就是將參數解出來。線程
詳細說下這個函數,首先看下這個函數中比較怪異的參數 ZEND_NUM_ARGS() TSRMLS_CC,這連個參數之間是空格的而不是逗號,進程
其實這個看下TSRMLS_CC的宏定義就能明白
#define TSRMLS_CC , TSRMLS_C //線程安全模式
#define TSRMLS_CC // 非線程安全模式
也就是說在線程安全模式下,TSRMLS_CC會被替換成 , TSRMLS_C 而且最終會被替換成,tsrm_ls ,分線程安全模式下,其實就是個空格
下面對於tsrm_ls 這個變量作說明。
在php源碼中常常會看到一些名詞,TSRM即線程安全資源管理器(Thread Safe Resource Manager),它在源碼的/TSRM目錄下面。通常狀況下,這個只會在被知名須要的時候纔會被啓用(好比,Apache2+worker MPM,一個基於線程的MPM),對於Win32下的Apache來講,是基於多線程的,因此這個層在Win32下老是被啓用的。ZTS即Zend線程安全(Zend Thread Safety),當TSRM被啓用的時候,就會定義這個名爲ZTS的宏。tsrm_ls 即TSRM存儲器(TSRM Local Storage),這個是在擴展和Zend中真正被實際使用的指代TSRM存儲的變量名。TSRMLS_開頭的宏通常有四個用來根據ZTS宏被定義與否來實現TSRM。4個宏以下:
#define TSRMLS_C tsrm_ls
#define TSRMLS_D void *** tsrm_ls
#define TSRMLS_CC ,tsrm_ls
#define TSRMLS_DS ,void ***tsrm_ls //注意有個逗號
php源碼用這麼複雜的宏保證線程安全,這主要是由於全局變量的緣由。簡單的說,咱們若是在兩個函數中處理一個變量,一種方式是使用全局,好比:
#include <stdio.h>
char *message;
void output_func(void){
printf("%s\n", message);
}
int main(int argv, char *argv[]){
message = argv[0];
output_func();
return 0;
}
通常的單線 程模型好比PHP CLI方式,Apache1,或者Apache2+prefork MPM(也是一種多進程模型),能夠放心的被使用,也不會出錯。全局變量在MINIT/RINIT的時候被建立,而後在整個進程運行時/請求處理期都能被 訪問到,而後在MSHUTDOW/RSHUTDOWN的時候被釋放。可是在多線程的模型下,這種方式就不在安全了,好比Apache2+worker MPM和IIS。在這種狀況下,全部的線程共享同一個進程的地址空間,也就說,多個線程共用一個全局變量,這個時候就會產生競爭。用C程序員的方式來講: 這個時候的全局變量是非線程安全的。
爲了解決這個問題,並和單線程模式兼容,Zend使用了稱做「Non_global Globals」的機制。這個機制的主要思想就是,對於多線程模型來講,每當一個新的線程被建立,就單獨的分配一塊內存,這塊內存存儲着一個全局變量的副 本。而這塊內存會被一個Vector串起來,由Zend統一管理。
這個連接是一個例子 http://www.luojisiwei-inc.com/archives/521
說了一大堆,其實要說是define的參數解析。其實以後就是一個將解析的參數複製過程。看代碼就很容易理解。
php 7 的define 內置函數解析,相對來講有點區別
#ifndef FAST_ZPP
if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|b", &name, &val, &non_cs) == FAILURE) {
return;
}
#else
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(name)
Z_PARAM_ZVAL(val)
Z_PARAM_OPTIONAL
Z_PARAM_BOOL(non_cs)
ZEND_PARSE_PARAMETERS_END();
#endif
默認php 7 在zend_API 中是定義了使用FAST_ZPP
也就是說,php7時候用了新的參數解析方式
ZEND_PARSE_PARAMETERS_START(2, 3) 是檢測參數個數
Z_PARAM_STR(name)
Z_PARAM_ZVAL(val) 這連個函數分別是調用不一樣的宏,用參數賦值變量,這段代碼用了大量的宏,一些變量在本宏中找不到的話,在前面的宏裏面找找