說明
這裡基於php7.2.5進行測試,php7之後內部結構變化應該不是太大,但與php5.X有差別。
我們接上一篇每天一個PHP語法-變數使用及內部實現再來說一下字串內建函式的實現。
函式分類
使用者自定義函式
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.len 記得嗎
#define ZSTR_LEN(zstr) (zstr)->len
// RETVAL_LONG 函式 給返回值賦值也就是 len 字串的長度,並把返回值的型別設定為 IS_LONG
小結
可以看到strlen其實是直接獲取了zval.zend_value.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
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程式碼是一樣的,也要定義、呼叫等步驟。
本作品採用《CC 協議》,轉載必須註明作者和本文連結