# 12.3 常量
在腳本中使用擴展的一個方便之處是,人們可以改變自己定義的常量。你可以通過define()函數來定義一個常量。在內核中,我們將會使用REGISTER_*_CONSTANT()的
家族函數來使用常量。
對于你定義的大多數常量來說,你可能希望在程序初始化的時候便定義這些變量。你可能需要在MINIT函數:
````c
PHP_MINIT_FUNCTION(sample4) {
REGISTER_STRING_CONSTANT("SAMPLE4_VERSION",
PHP_SAMPLE4_EXTVER, CONST_CS | CONST_PERSISTENT);
return SUCCESS;
}
````
第一個參數是你要定義的這個常量的名字。在例子中,我們定義了一個名稱為SAMPLE4_VERSION的常量。有一點很重要,這里要注意宏REGISTER_*_CONSTANT()的
使用,這些函數中為了確定常量的名稱長度使用了sizeof()。這就意味著,常量的名稱只能為文字,大家可以嘗試使用一個char *的變量,這將導致sizeof計算出錯誤
的字符串長度。
接下來,我們來看看常量的值。在大多數情況下,它會是一個單一參數的類型,然而在STRINGL的版本中,你會看到在一些情況下會需要使用第二個參數來表明長度。
當注冊string類型的常量時,字符串的值不會被復制到常量中,而僅僅是一個引用。這意味著,動態創建的字符串需要持久化和在shutdown的階段被釋放掉。
最后,在最后一個參數,你可以通過兩個可以標識位的按位或組合傳入。CONST_CS標識是否大小寫敏感,一般情況下CONST_CS標識是默認使用的。對于一些特殊的
情況,比如TRUE,FALSE,NULL等等,這個參數將被省略。
在|后的標識位中的標識符說明了該常量的作用域和生命周期。當我們在MINIT中定義常量時,你可能需要在多個請求中使用這個常量,當你在RINIT中定義常量時,這個
常量會在當前請求結束的時候銷毀。
下面列出的4個創建常量常用的函數,有一個共同需要注意的地方,常量名稱一定要用文字而不是char *類型的變量。
````c
REGISTER_LONG_CONSTANT(char *name, long lval, int flags)
REGISTER_DOUBLE_CONSTANT(char *name, double dval, int flags)
REGISTER_STRING_CONSTANT(char *name, char *value, int flags)
REGISTER_STRINGL_CONSTANT(char *name,char *value, int value_len, int flags)
````
如果你沒有辦法提供文本類型的name,那么你可以嘗試使用上面4個函數的底層函數去實現相同的效果:
````c
void zend_register_long_constant(char *name, uint name_len, long lval, int flags, int module_number TSRMLS_DC)
void zend_register_double_constant(char *name, uint name_len, double dval, int flags, int module_number TSRMLS_DC)
void zend_register_string_constant(char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC)
void zend_register_stringl_constant(char *name, uint name_len, char *strval, uint strlen, int flags,int module_number TSRMLS_DC)
````
這樣就可以由傳入name_len而擴大了該族函數的使用范圍(比如在循環中)。
module_number是一個加載擴展或者卸載擴展時的標識。而你不需要關注它,它會自動加載到你擴展中的MINIT和RINIT中,所以在你用上面4個函數聲明常量的時候,
你可以這樣寫:
````c
PHP_MINIT_FUNCTION(sample4) {
register_string_constant("SAMPLE4_VERSION",
sizeof("SAMPLE4_VERSION"),
PHP_SAMPLE4_EXTVER,
CONST_CS | CONST_PERSISTENT,
module_number TSRMLS_CC);
return SUCCESS;
}
````
除了數組和對象外,其他變量你也可以用來注冊一個常量,但是因為沒有宏和ZEND API去支持這些聲明,所以你必須手動聲明一個常量,通過下面一個例子來了解一下:
````c
void php_sample4_register_boolean_constant(char *name, uint len,
zend_bool bval, int flags, int module_number TSRMLS_DC)
{
zend_constant c;
ZVAL_BOOL(&c.value, bval);
c.flags = CONST_CS | CONST_PERSISTENT;
c.name = zend_strndup(name, len - 1);
c.name_len = len;
c.module_number = module_number;
zend_register_constant(&c TSRMLS_CC);
}
````
## links
* [目錄](<preface.md>)
* 12.2 [MINFO與phpinfo](<12.2.md>)
* 12.4 [PHP擴展中的全局變量](<12.4.md>)
- about
- 開始閱讀
- 目錄
- 1 PHP的生命周期
- 1.讓我們從SAPI開始
- 2.PHP的啟動與終止
- 3.PHP的生命周期
- 4.線程安全
- 5.小結
- 2 PHP變量在內核中的實現
- 1. 變量的類型
- 2. 變量的值
- 3. 創建PHP變量
- 4. 變量的存儲方式
- 5. 變量的檢索
- 6. 類型轉換
- 7. 小結
- 3 內存管理
- 1. 內存管理
- 2. 引用計數
- 3. 總結
- 4 動手編譯PHP
- 1. 編譯前的準備
- 2. PHP編譯前的config配置
- 3. Unix/Linux平臺下的編譯
- 4. 在Win32平臺上編譯PHP
- 5. 小結
- 5 Your First Extension
- 1. 一個擴展的基本結構
- 2. 編譯我們的擴展
- 3. 靜態編譯
- 4. 編寫函數
- 5. 小結
- 6 函數返回值
- 1. 一個特殊的參數:return_value
- 2. 引用與函數的執行結果
- 3. 小結
- 7 函數的參數
- 1. zend_parse_parameters
- 2. Arg Info 與類型綁定
- 3. 小結
- 8 使用HashTable與{數組}
- 1. 數組(C中的)與鏈表
- 2. 操作HashTable的API
- 3. 在內核中操作PHP語言中數組
- 4. 小結
- 9 PHP中的資源類型
- 1. 復合類型的數據——{資源}
- 2. Persistent Resources
- 3. {資源}自有的引用計數
- 4. 小結
- 10 PHP中的面向對象(一)
- 1. zend_class_entry
- 2. 定義一個類
- 3. 定義一個接口
- 4. 類的繼承與接口的實現
- 5. 小結
- 11 PHP中的面向對象(二)
- 1. 生成對象的實例與調用方法
- 2. 讀寫對象的屬性
- 3. 小結
- 12 啟動與終止的那點事
- 2. 小結
- 1. 關于生命周期
- 2. MINFO與phpinfo
- 3. 常量
- 4. PHP擴展中的全局變量
- 5. PHP語言中的超級全局變量
- 6. 小結
- 13 INI設置
- 1. 聲明和訪問ini設置
- 2. 小結
- 2. 小結
- 14 流式訪問
- 1. 概覽
- 2. 打開流
- 3. 訪問流
- 4. 靜態資源操作
- 5. 小結
- 15 流的實現
- 1. php流的表象之下
- 2. 包裝器操作
- 3. 實現一個包裝器
- 4. 操縱
- 5. 檢查
- 6. 小結
- 16 有趣的流
- 1. 上下文
- 2. 過濾器
- 3. 小結
- 17 配置和鏈接
- 1. autoconf
- 2. 庫的查找
- 3. 強制模塊依賴
- 4. Windows方言
- 5. 小結
- 18 擴展生成
- 1. ext_skel
- 2. PECL_Gen
- 3. 小結
- 19 設置宿主環境
- 1. 嵌入式SAPI
- 2. 構建并編譯一個宿主應用
- 3. 通過嵌入包裝重新創建cli
- 4. 老技術新用
- 5. 小結
- 20 高級嵌入式
- 1. 回調到php中
- 2. 錯誤處理
- 3. 初始化php
- 4. 覆寫INI_SYSTEM和INI_PERDIR選項
- 5. 捕獲輸出
- 6. 同時擴展和嵌入
- 7. 小結
- 約定