說明 這裡基於 php7.2.5 進行測試,php7 之後內部結構變化應該不是太大,但與 php5.X 有差別。 函數分類 用戶自定義函數 say(); function say() { echo "周傑倫"; } php hello.php 周傑倫 cli 模式下我們執行這個代碼之後就會輸出函數調 ...
說明
這裡基於 php7.2.5 進行測試,php7 之後內部結構變化應該不是太大,但與 php5.X 有差別。
函數分類
用戶自定義函數
say(); function say() { echo "周傑倫"; }
php hello.php 周傑倫
cli 模式下我們執行這個代碼之後就會輸出函數調用的結果,簡單來說這個過程經歷了下麵的步驟
我們可以先理解為要經歷編譯、執行兩步。也就是我們每次執行這段代碼都要經歷這樣的一個過程。
內置函數
也就是我們在手冊中看到的函數,太多了,這裡我們用字元串函數來舉例說明。與用戶自定義函數不同,內置函數不需要經歷編譯,直接定義註冊就可以。
所以內置函數的效率相對是高一些。
函數如何實現的
strlen
strlen("hello"); // 這個語法不說了,返回字元串長度
// 看一下具體實現 // Zend/zend_builtin_functions.c ZEND_FUNCTION(strlen) // 定義函數 strlen是函數名 { zend_string *s; // 這是參數字元串 ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(s) ZEND_PARSE_PARAMETERS_END(); // 主要看這裡 給返回值設置的是 s的長度 RETVAL_LONG(ZSTR_LEN(s)); } // 來看下ZSTR_LEN是啥 // zend_string.h // 很巧返回的是zend_value.zend_string.len 記得嗎 #define ZSTR_LEN(zstr) (zstr)->len // RETVAL_LONG 函數 給返回值賦值也就是 len 字元串的長度,並把返回值的類型設置為 IS_LONG
小結
可以看到 strlen 其實是直接獲取了 zval.zend_value.zend_string.len, 最後一步是把 len 賦值給函數返回值。
這裡需要說明的是:
- ZEND_FUNCTION 是函數聲明的通用格式,知道就行。
- 函數返回值也是一個變數,函數執行完返回它。
strcmp
strcmp($str1, $str2); //這個函數是比較兩個字元串的大小,如果str1>str2則大於0,如果str1<str2則小於0,如果str1=str2則等於0 strcmp("ha", "h");// 1 多一個字元 strcmp("ha","hA");// 32 這個32是咋來的呢,實際上如果字元數量相等則比較第二個字元的ASII值,看下麵 echo ord("A"); // 65 echo PHP_EOL; echo ord("a"); // 97
// 來看實現 // 定義函數 ZEND_FUNCTION(strcmp) { // 參數 s1=ha, s2=h zend_string *s1, *s2; // 這裡設置參數 ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_STR(s1) Z_PARAM_STR(s2) ZEND_PARSE_PARAMETERS_END(); // 這裡進行比較, 調用zend_binary_strcmp進行比較 // 參數為s1的值也就是ha, s1的長度也就是2, s2的值h, s2的長度 1 // ZEND_LEN就是返回s2的長度,看上面的內容 RETURN_LONG(zend_binary_strcmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2))); } // 來看zend_binary_strcmp ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */ { // 返回值 int retval; // 如果完全相等就是0, == 在任何語言都適合 if (s1 == s2) { return 0; } // 調用c內置函數memcmp比較 // min(len1, len2) 是獲取最短的那個長度 // 如min("ha", "h") 就比較前1個字元 retval = memcmp(s1, s2, MIN(len1, len2)); // 如果=0則再min長度內是相等的,返回值就是哪個長就返回多出來的字元數 if (!retval) { return (int)(len1 - len2); } else { // 如果<>0,則就返回那個值 return retval; } } // 關於memcmp 在c官方手冊看到 , 比較兩個字元串,s1>s2返回大於0,s1<s2返回小於0, s1=s2返回0 // 參考 // 就是把每個字元都比較一遍 int memcmp(const void *s1, const void *s2, size_t n){ const unsigned char *su1, *su2; for(su1 = s1, su2 = s2; 0 < n; ++su1, ++su2, --n) if(*su1 != *su2) return ((*su1 < *su2) ? -1 : +1); return 0; }
小結
strcmp 的實現是基於 C 內置函數 memcmp 實現的,規則就是 memcmp 的語法。
總結
內置函數不需要經歷編譯過程,執行速度比自定義函數要快,實現上跟我們寫 PHP 代碼是一樣的,也要定義、調用等步驟。