常用的php函式的實現和介紹

才智咖 人氣:2W

常用php函式實現及介紹

常用的php函式的實現和介紹

count

count是我們經常用到的一個函式,其功能是返回一個數組的長度。

count這個函式,其複雜度是多少呢? 一種常見的說法是count函式會遍歷整個陣列然後求出元素個數,因此複雜度是O(n)。那實際情況是不是這樣呢?我們回到count的實現來看一下,通過原始碼可以發現,對於陣列的count操作,

函式最終的路徑是zif_count-> php_count_recursive-> zend_hash_num_elements,而zend_hash_num_elements的行為是 return ht->nNumOfElements,

可見,這是一個O(1)而不是O(n)的操作。實際上,陣列在php底層就是一個hash_table,對於hash表,zend中專門有一個元素nNumOfElements記錄了當前元素的個數,因此對於一般的count實際上直接就返回了這個值。由此,我們得出結論: count是O(1)的複雜度,和具體陣列的大小無關。

非陣列型別的變數,count的行為時怎樣?對於未設定變數返回0,而像int、double、string等則會返回1

strlen

Strlen用於返回一個字串的長度。那麼,他的實現原理是如何的呢?我們都知道在c中strlen是一個o(n)的函式,會順序遍歷字串直到遇到,然後出長度。Php中是否也這樣呢?答案是否定的,php裡字串是用一個複合結構來描述,

包括指向具體資料的指標和字串長度(和c++中string類似),因此 strlen就直接返回字串長度了,是常數級別的操作。另外,對於非字串型別的變數呼叫strlen,它會首先將變數強制轉換為字串再求長度,這點需要注意。

isset和array_key_exists

這兩個函式最常見的用法都是判斷一個 key是否在陣列中存在。但是前者還可以用於判斷一個變數是否被設定過。如前文所述,isset並非真正的函式,因此它的效率會比後者高很多。推薦用它代替array_key_exists。

array_push和array[]

兩者都是往陣列尾部追加一個元素。不同的是前者可以一次push多個。他們最大的'區別在於一個是函式一個是語言結構,因此後者效率要更高。因此如果只是普通的追加元素,建議使用array []。

rand和mt_rand

兩者都是提供產生隨機數的功能,前者使用 libc標準的rand。後者用了 Mersenne Twister 中已知的特性作為隨機數發生器,它可以產生隨機數值的平均速度比 libc 提供的 rand() 快四倍。因此如果對效能要求較高,可以考慮用mt_rand代替前者。

我們都知道,rand產生的是偽隨機數,在C中需要用srand顯示指定種子。但是在php中,rand會自己幫你預設呼叫一次srand,一般情況下不需要自己再顯示的呼叫。需要注意的是,如果特殊情況下需要呼叫srand時,一定要配套呼叫。

就是說srand對於rand,mt_srand對應srand,切不可混合使用,否則是無效的。

sort和 usort

兩者都是用於排序,不同的是前者可以指定排序策略,類似我們C裡面的qsort和C++的sort。在排序上兩者都是採用標準的快排來實現,對於有排序需求的,如非特殊情況呼叫php提供的這些方法就可以了,不用自己重新實現一遍,

效率會低很多。原因見前文對於使用者函式和內建函式的分析比對。

urlencode和rawurlencode

這兩個都是用於 url編碼, 字串中除了 -_. 之外的所有非字母數字字元都將被替換成百分號(%)後跟兩位十六進位制數。兩者唯一的區別在於對於空格,urlencode會編碼為+,而 rawurlencode會編碼為。

一般情況下除了搜尋引擎,我們的策略都是空格編碼為。因此採用後者的居多。注意的是encode和 decode系列一定要配套使用。

strcmp系列函式

這一系列的函式包括strcmp、 strncmp、strcasecmp、strncasecmp,實現功能和C函式相同。但也有不同,由於php的字串是允許出現,因此在判斷的時候底層使用的是memcmp系列而非strcmp,

理論上來說更快。另外由於php直接能獲取到字串長度,因此會首先這方面的檢查,很多情況下效率就會高很多了。

is_int和is_numeric

這兩個函式功能相似又不完全相同,使用的時候一定需要注意他們的區別。Is_int:判斷一個變數型別是否是整數型,php變數中專門有一個欄位表徵型別,因此直接判斷這個型別即可,

是一個絕對 O(1)的操作 Is_numeric:判斷一個變數是否是整數或數字字串,也就是說除了整數型變數會返回true之外,對於字串變數,如果形如”1234”,”1e4”等也會被判為true。這個時候會遍歷字串進行判斷。

總結及建議

總結:

通過對函式實現的原理分析和效能測試,我們總結出以下一些結論

1. Php的函式呼叫開銷相對較大。

2. 函式相關資訊儲存在一個大的hash_table中,每次呼叫時通過函式名在hash表中查詢,因此函式名長度對效能也有一定影響。

3. 函式返回引用沒有實際意義

4. 內建php函式效能比使用者函式高很多,尤其對於字串類操作。

5. 類方法、普通函式、靜態方法效率幾乎相同,沒有太大差異

6. 除去空函式呼叫的影響,內建函式和同樣功能的C函式效能基本差不多。

7. 所有的引數傳遞都是採用引用計數的淺拷貝,代價很小。

8. 函式個數對效能影響幾乎可以忽略

建議:

因此,對於php函式的使用,有如下一些建議

1. 一個功能可以用內建函式完成,儘量使用它而不是自己編寫php函式。

2. 如果某個功能對效能要求很高,可以考慮用擴充套件來實現。

3. Php函式呼叫開銷較大,因此不要過分封裝。有些功能,如果需要呼叫的次數很多本身又只用1、2行程式碼就行實現的,建議就不要封裝呼叫了。

4. 不要過分迷戀各種設計模式,如上一條描述,過分的封裝會帶來效能的下降。需要考慮兩者的權衡。Php有自己的特點,切不可東施效顰,過分效仿java的模式。

5. 函式不宜巢狀過深,遞迴使用要謹慎

6. 偽函式效能很高,同等功能實現下優先考慮。比如用isset代替array_key_exists

7. 函式返回引用沒有太大意義,也起不到實際作用,建議不予考慮。

8. 類成員方法效率不比普通函式低,因此不用擔心效能損耗。建議多考慮靜態方法,可讀性及安全性都更好。

9. 如不是特殊需要,引數傳遞都建議使用傳值而不是傳引用。當然,如果引數是很大的陣列且需要修改時可以考慮引用傳遞。

TAGS:PHP 函式