PHP 語法字符串函數 strcmp、strlen 使用及實現

說明

這裏基於 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 代碼是一樣的,也要定義、調用等步驟。

更多學習內容請訪問:

騰訊T3-T4標準精品PHP架構師教程目錄大全,只要你看完保證薪資上升一個臺階(持續更新)圖標

以上內容希望幫助到大家,很多PHPer在進階的時候總會遇到一些問題和瓶頸,業務代碼寫多了沒有方向感,不知道該從那裏入手去提升,對此我整理了一些資料,包括但不限於:分佈式架構、高可擴展、高性能、高併發、服務器性能調優、TP6,laravel,YII2,Redis,Swoole、Swoft、Kafka、Mysql優化、shell腳本、Docker、微服務、Nginx等多個知識點高級進階乾貨需要的可以免費分享給大家,需要的可以加入我的官方羣點擊此處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章