PHP中有一個非常常見的函數strpos,它被廣泛地用于字符串的查找和匹配功能。它的用法非常簡單,只需要傳入兩個參數,一個是待查找的字符串,另一個是需要查找的字符串。該函數會返回需要查找的字符串在待查找的字符串中第一次出現的位置,如果找不到則返回false。
接下來我們來看一下strpos函數的源碼。函數的定義如下:
function strpos($haystack, $needle, $offset = 0) { return call_user_func_array('strpos', func_get_args()); }
由上可見,這里并沒有具體實現函數邏輯,而是調用了call_user_func_array這個函數,并將其參數轉換為數組傳入。接下來我們需要看一下調用的call_user_func_array函數的定義:
function call_user_func_array($function, $param_arr) { if (!function_exists($function)) { user_error("Function {$function}() does not exist", E_USER_WARNING); return null; } $params = array(); foreach ($param_arr as $key => $value) { $params[] = &$param_arr[$key]; } return call_user_func_array($function, $params); }
call_user_func_array的作用是動態調用函數,并將參數轉換為數組形式作為參數傳入。如果需要調用的函數不存在,則會返回一個錯誤提示。在這里,call_user_func_array的參數為'strpos'和一個數組,這里的strpos實際上是指PHP內置函數strpos。
再來看一下PHP內置函數strpos的定義:
function strpos($haystack, $needle, $offset = 0) { return mb_strpos($haystack, $needle, $offset, 'UTF-8'); }
我們可以看到,實際上PHP內置的strpos函數并沒有具體實現查找邏輯,而是調用了mb_strpos函數,并將命中的結果直接返回。
函數mb_strpos的定義如下:
function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return mb_stripos($haystack, $needle, $offset, $encoding); }
mb_strpos函數實際上也并沒有具體實現查找邏輯,而是調用了mb_stripos函數,并將其結果直接返回。這里需要注意的是,mb_strpos的$encoding參數的默認值為null,這意味著函數將使用php.ini文件中的默認編碼。如果$encoding參數被設置為了其它值,則函數將使用指定的編碼進行查找。
下面我們來看一下mb_stripos函數的定義:
function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return iconv_strpos(strtolower($haystack), strtolower($needle), $offset); }
mb_stripos函數最終實現了我們需要的查找邏輯。具體來說,函數調用了iconv_strpos函數進行查找。在查找之前,函數還將待查找的字符串和需要查找的字符串都轉換為了小寫字母,這是為了避免大小寫不一致的問題。
最后我們來看一下iconv_strpos函數的定義:
function iconv_strpos($haystack, $needle, $offset = 0) { $match = iconv_strrpos($haystack, $needle, -$offset); return $match === false ? false : $match + $offset; }
iconv_strpos實際上就是具體的查找邏輯了,它使用了PHP內置的iconv函數進行查找。該函數會返回需要查找的字符串在待查找的字符串中第一次出現的位置,如果找不到則返回false。
因此,我們可以將整個查找邏輯總結為以下代碼:
function iconv_strpos($haystack, $needle, $offset = 0) { $match = iconv_strrpos($haystack, $needle, -$offset); return $match === false ? false : $match + $offset; } function mb_stripos($haystack, $needle, $offset = 0, $encoding = null) { return iconv_strpos(strtolower($haystack), strtolower($needle), $offset); } function mb_strpos($haystack, $needle, $offset = 0, $encoding = null) { return mb_stripos($haystack, $needle, $offset, $encoding); } function strpos($haystack, $needle, $offset = 0) { return mb_strpos($haystack, $needle, $offset, 'UTF-8'); }
在使用strpos函數時,我們可以不用具體了解其底層的實現邏輯,只需知道它能夠成功查找需要查找的字符串在待查找的字符串中第一次出現的位置即可。但如果我們需要自己實現一個類似的函數,或者需要對其進行定制化的修改時,了解其底層實現邏輯就很必要了。
最后需要注意的是,在PHP 8中,strpos函數已經被廢棄,推薦使用str_contains或str_starts_with等函數進行字符串查找。