【php原理】大話php常量

來源:互聯網
上載者:User

標籤:php原理   zend   

我們先看一個php常量的定義方法

define(‘PRICE‘, 30);

 之前,我一直把define和C中的宏定義理解一致,因此在使用的時候也只是將其當成簡單地字元替換。後來研究了PHP核心以後,發現PHP中的常量和宏定義完全不是一回事。

在PHP指令碼啟動並執行過程中,zend引擎會維護一個常量列表,對於普通使用者來說,可以對這個常量列表進行CRUD操作,api分別為

define():定義一個常量

defined(): 判斷一個常量是否存在

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

我們來看下PHP核心中常量的定義

typedef struct _zend_constant{zval value;int flags;char *name;uint name_len;int module_number;} _zend_constant;

 其中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中):

/* {{{ proto bool define(string constant_name, mixed value, boolean case_insensitive=false)   Define a new constant */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;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;case IS_OBJECT: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 = IS_INTERNED(name) ? name : zend_strndup(name, name_len);if(c.name == NULL) {RETURN_FALSE;}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;}}/* }}} */

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.