九個你需要知道的PHP函數和功能
來源:互聯網
上載者:User
9個你需要知道的PHP函數和功能
即使使用 PHP 多年,有些功能和特點我們也未必發現或未被充分利用,一旦被我們發現,就會發現它們非常有用。然而,並不是所有的人都已經從頭至尾詳讀過 PHP 的手冊和功能參考!
1. 函數與任意數量的參數
您可能已經知道,PHP 允許我們定義選擇性參數的函數。但也有完全允許任意數量的函數參數方法。
首先,下面這個例子只是選擇性參數:
view sourceprint?01 // function with 2 optional arguments
02 function foo($arg1 = '', $arg2 = '') {
03 echo "arg1: $arg1\n";
04 echo "arg2: $arg2\n";
05 }
06 foo('hello','world');
07 /* prints:
08 arg1: hello
09 arg2: world
10 */
11 foo();
12 /* prints:
13 arg1:
14 arg2:
15 */
現在,讓我們看看如何可以建立一個函數接受任何數量的參數。這一次,我們要利用 func_get_args() 函數:
view sourceprint?01 // yes, the argument list can be empty
02 function foo() {
03 // returns an array of all passed arguments
04 $args = func_get_args();
05 foreach ($args as $k => $v) {
06 echo "arg".($k+1).": $v\n";
07 }
08 }
09 foo();
10 /* prints nothing */
11 foo('hello');
12 /* prints
13 arg1: hello
14 */
15 foo('hello', 'world', 'again');
16 /* prints
17 arg1: hello
18 arg2: world
19 arg3: again
20 */
2. 使用 Glob() 函數來尋找檔案
許多 PHP 內建函數有非常長的命名。然而,它可能會很難說明是什麼作用的函數,如果不使用 Glob() 來做,除非你已經非常熟悉這個函數。
它更像是 scandir() 函數加強型版本。它可以讓您通過使用模式搜尋檔案。
view sourceprint?01 // get all php files
02 $files = glob('*.php');
03 print_r($files);
04 /* output looks like:
05 Array
06 (
07 [0] => phptest.php
08 [1] => pi.php
09 [2] => post_output.php
10 [3] => test.php
11 )
12 */
這樣你可以獲得多個檔案類型:
view sourceprint?01 // get all php files AND txt files
02 $files = glob('*.{php,txt}', GLOB_BRACE);
03 print_r($files);
04 /* output looks like:
05 Array
06 (
07 [0] => phptest.php
08 [1] => pi.php
09 [2] => post_output.php
10 [3] => test.php
11 [4] => log.txt
12 [5] => test.txt
13 )
14 */
請注意,這些檔案其實是可以返回一個路徑的,根據你的查詢。
view sourceprint?1 $files = glob('../images/a*.jpg');
2 print_r($files);
3 /* output looks like:
4 Array
5 (
6 [0] => ../images/apple.jpg
7 [1] => ../images/art.jpg
8 )
9 */
如果你想獲得每個檔案的完整路徑,你可以調用 realpath() 函數來返回。
view sourceprint?01 $files = glob('../images/a*.jpg');
02 // applies the function to each array element
03 $files = array_map('realpath',$files);
04 print_r($files);
05 /* output looks like:
06 Array
07 (
08 [0] => C:\wamp\www\images\apple.jpg
09 [1] => C:\wamp\www\images\art.jpg
10 )
11 */
3. 記憶體使用量資訊
通過觀察你的指令碼記憶體使用方式,你就可以將你的代碼進行針對性最佳化。
PHP 有一個垃圾收集器和一個相當複雜的記憶體管理器。當你的指令碼開始就開始正式使用記憶體。也會根據指令碼的執行情況,記憶體使用量量會上升也會下降。為了得到當前記憶體使用量情況,我們就可以使用 memory_get_usage() 函數。並可以在任何時候得到記憶體使用量的最高點,下面就是使用 memory_get_usage() 函數的例子。
view sourceprint?01 echo "Initial: ".memory_get_usage()." bytes \n";
02 /* prints
03 Initial: 361400 bytes
04 */
05 // let's use up some memory
06 for ($i = 0; $i < 100000; $i++) {
07 $array []= md5($i);
08 }
09 // let's remove half of the array
10 for ($i = 0; $i < 100000; $i++) {
11 unset($array[$i]);
12 }
13 echo "Final: ".memory_get_usage()." bytes \n";
14 /* prints
15 Final: 885912 bytes
16 */
17 echo "Peak: ".memory_get_peak_usage()." bytes \n";
18 /* prints
19 Peak: 13687072 bytes
20 */
4. CPU 的使用資訊
為此,我們就要利用 getrusage() 函數。請記住,這個函數不能應用於 windows 平台。
view sourceprint?01 print_r(getrusage());
02 /* prints
03 Array
04 (
05 [ru_oublock] => 0
06 [ru_inblock] => 0
07 [ru_msgsnd] => 2
08 [ru_msgrcv] => 3
09 [ru_maxrss] => 12692
10 [ru_ixrss] => 764
11 [ru_idrss] => 3864
12 [ru_minflt] => 94
13 [ru_majflt] => 0
14 [ru_nsignals] => 1
15 [ru_nvcsw] => 67
16 [ru_nivcsw] => 4
17 [ru_nswap] => 0
18 [ru_utime.tv_usec] => 0
19 [ru_utime.tv_sec] => 0
20 [ru_stime.tv_usec] => 6269
21 [ru_stime.tv_sec] => 0
22 )
23 */
這看起來蠻神秘的,有些艱澀難懂,除非你已經有過系統管理員的經驗,以下是每個值的介紹(或許你並不需要記住這些):
ru_oublock:塊輸出操作
ru_inblock:塊輸入操作
ru_msgsnd:郵件發送
ru_msgrcv:收到的郵件
ru_maxrss:最大駐留集大小
ru_ixrss:積分共用記憶體的大小
ru_idrss:積分大小非共用資料
ru_minflt:頁回收
ru_majflt:分頁錯誤
ru_nsignals:訊號接收
ru_nvcsw:自動環境切換
ru_nivcsw:非自動的環境切換
ru_nswap:到期
ru_utime.tv_usec:使用者使用時間(微秒)
ru_utime.tv_sec:使用者使用時間(秒)
ru_stime.tv_usec:系統使用時間(微秒)
ru_stime.tv_sec:系統使用時間(秒)
要看 CPU 的功率有多少被指令碼消耗,我們需要觀察 user time 和 system time 的值。秒和毫秒是預設獨立提供的。你可以將 100 萬毫秒的值,並將其換算成秒的值,將它當做一個十進位數的總秒數。
讓我們看一個例子:
view sourceprint?01 // sleep for 3 seconds (non-busy)
02 sleep(3);
03 $data = getrusage();
04 echo "User time: ".
05 ($data['ru_utime.tv_sec'] +
06 $data['ru_utime.tv_usec'] / 1000000);
07 echo "System time: ".
08 ($data['ru_stime.tv_sec'] +
09 $data['ru_stime.tv_usec'] / 1000000);
10 /* prints
11 User time: 0.011552
12 System time: 0
13 */
雖然指令碼大約花了 3 秒鐘的時間來運行, CPU 的使用率還是非常非常低的。因為 sleep 工作,指令碼實際上並沒有消耗 CPU 資源。當然還有其他的任務可能真正需要等待時間,但千萬不能用磁碟的讀取寫入操作來等待 CPU 時間。所以你可以發現, CPU 使用率和運行時的實際長度並不是總是一樣的。
下面是另外一個例子。
view sourceprint?01 // loop 10 million times (busy)
02 for($i=0;$i< 10000000;$i++) {
03 }
04 $data = getrusage();
05 echo "User time: ".
06 ($data['ru_utime.tv_sec'] +
07 $data['ru_utime.tv_usec'] / 1000000);
08 echo "System time: ".
09 ($data['ru_stime.tv_sec'] +
10 $data['ru_stime.tv_usec'] / 1000000);
11 /* prints
12 User time: 1.424592
13 System time: 0.004204
14 */
這花了大約 1.4 秒的 CPU 時間。幾乎所有這些都是由使用者操作所用的時間,系統並沒有被調用。
系統時間是劃分時間的 CPU 上執行的程式的代表的核心系統調用時間。(誰有更簡明扼要的描述?help!)下面是一個例子:
view sourceprint?01 $start = microtime(true);
02 // keep calling microtime for about 3 seconds
03 while(microtime(true) - $start < 3) {
04 }
05 $data = getrusage();
06 echo "User time: ".
07 ($data['ru_utime.tv_sec'] +
08 $data['ru_utime.tv_usec'] / 1000000);
09 echo "System time: ".
10 ($data['ru_stime.tv_sec'] +
11 $data['ru_stime.tv_usec'] / 1000000);
12 /* prints
13 User time: 1.088171
14 System time: 1.675315
15 */
5. 魔術常量
PHP 提供了擷取當前行號的方法 (__LINE__),擷取檔案路徑方法(__FILE__),目錄(__DIR__),函數名(__FUNCTTION__),類名(__CLASS__),方法名(__METHOD__),和命名空間(__NAMESPACE__)。以上就是常用的魔術常量。恐怕我們最常用的就只有 (__FILE__) 了。
Rikku 不打算全部進行說明,但會說幾個用例。
當然包括了其他的指令碼,這是個不錯的主意。((__DIR__)需要 PHP 5.3 以上版本):
view sourceprint?1 // this is relative to the loaded script's path
2 // it may cause problems when running scripts from different directories
3 require_once('config/database.php');
4 // this is always relative to this file's path
5 // no matter where it was included from
6 require_once(dirname(__FILE__) . '/config/database.php');
使用 __LINE__ 讓調試更加容易,你可以跟蹤行號:
view sourceprint?01 // some code
02 // ...
03 my_debug("some debug message", __LINE__);
04 /* prints
05 Line 4: some debug message
06 */
07 // some more code
08 // ...
09 my_debug("another debug message", __LINE__);
10 /* prints
11 Line 11: another debug message
12 */
13 function my_debug($msg, $line) {
14 echo "Line $line: $msg\n";
15 }
6. 產生唯一的ID
有些情況下,您需要產生一股唯一的字串。我看到很多人會用這個 md5() 函數,即使他並不完全用於此目的的存在:
view sourceprint?1 // generate unique string
2 echo md5(time() . mt_rand(1,1000000));
其實有個專門的 PHP 函數,名為 uniqid() 就是為了這個目的而存在的:
view sourceprint?01 // generate unique string
02 echo uniqid();
03 /* prints
04 4bd67c947233e
05 */
06 // generate another unique string
07 echo uniqid();
08 /* prints
09 4bd67c9472340
10 */
您可能會注意到,即使是唯一的字串,他們的前幾個字元很相似。這是因為產生的字串是關聯到伺服器時間的。設實際上有一個非常好的副作用,因為每個新產生的 ID 將在產生後按字母順序排列,這樣也省去了我們排序的邏輯動作。
為了減少重複的幾率,你可以傳遞一個首碼,或在第二個參數來增加。
view sourceprint?01 // with prefix
02 echo uniqid('foo_');
03 /* prints
04 foo_4bd67d6cd8b8f
05 */
06 // with more entropy
07 echo uniqid('',true);
08 /* prints
09 4bd67d6cd8b926.12135106
10 */
11 // both
12 echo uniqid('bar_',true);
13 /* prints
14 bar_4bd67da367b650.43684647
15 */
此功能將會產生比 md5() 產生的字串更短,這也將節省您的空間。
7. 序列化
你有沒有需要儲存在資料庫中複雜的變數或者大文字檔?那你有沒有拿出一個解決方案,花式轉換成格式化的字串數組或對象的?別擔心,PHP 已經為我們準備好了這個功能。
有兩種序列化的方法,下面是一個例子,它使用 serialize() 進行序列化和 unserialize() 進行解除序列化:
view sourceprint?01 // a complex array
02 $myvar = array(
03 'hello',
04 42,
05 array(1,'two'),
06 'apple'
07 );
08 // convert to a string
09 $string = serialize($myvar);
10 echo $string;
11 /* prints
12 a:4:{i:0;s:5:"hello";i:1;i:42;i:2;a:2:{i:0;i:1;i:1;s:3:"two";}i:3;s:5:"apple";}
13 */
14 // you can reproduce the original variable
15 $newvar = unserialize($string);
16 print_r($newvar);
17 /* prints
18 Array
19 (
20 [0] => hello
21 [1] => 42
22 [2] => Array
23 (
24 [0] => 1
25 [1] => two
26 )
27 [3] => apple
28 )
29 */
這是原生態的 PHP 序列化方法。然而,由於 JSON 近年來已經大受歡迎,PHP 5.2 中也決定添加對它們的支援。現在你可以使用 json_encode() 和 json_decode() 函數來完成這項工作:
view sourceprint?01 // a complex array
02 $myvar = array(
03 'hello',
04 42,
05 array(1,'two'),
06 'apple'
07 );
08 // convert to a string
09 $string = json_encode($myvar);
10 echo $string;
11 /* prints
12 ["hello",42,[1,"two"],"apple"]
13 */
14 // you can reproduce the original variable
15 $newvar = json_decode($string);
16 print_r($newvar);
17 /* prints
18 Array
19 (
20 [0] => hello
21 [1] => 42
22 [2] => Array
23 (
24 [0] => 1
25 [1] => two
26 )
27 [3] => apple
28 )
29 */
這麼做看起來會更加緊湊。當然它對其他語言如 javascript 相容性也是最好的。然而,您需要注意的是:對於某些複雜的對象,某些資訊會無故丟失!
8. 壓縮字串
在談到壓縮時,我們通常會想到一些檔案,如 zip 檔案。它可以在 PHP 中壓縮長字串,並且不涉及任何封存檔案。
在下面的例子中,我們要利用 gzcompress() 和 gzuncompress() 函數:
view sourceprint?01 $string =
02 "Lorem ipsum dolor sit amet, consectetur
03 adipiscing elit. Nunc ut elit id mi ultricies
04 adipiscing. Nulla facilisi. Praesent pulvinar,
05 sapien vel feugiat vestibulum, nulla dui pretium orci,
06 non ultricies elit lacus quis ante. Lorem ipsum dolor
07 sit amet, consectetur adipiscing elit. Aliquam
08 pretium ullamcorper urna quis iaculis. Etiam ac massa
09 sed turpis tempor luctus. Curabitur sed nibh eu elit
10 mollis congue. Praesent ipsum diam, consectetur vitae
11 ornare a, aliquam a nunc. In id magna pellentesque
12 tellus posuere adipiscing. Sed non mi metus, at lacinia
13 augue. Sed magna nisi, ornare in mollis in, mollis
14 sed nunc. Etiam at justo in leo congue mollis.
15 Nullam in neque eget metus hendrerit scelerisque
16 eu non enim. Ut malesuada lacus eu nulla bibendum
17 id euismod urna sodales. ";
18 $compressed = gzcompress($string);
19 echo "Original size: ". strlen($string)."\n";
20 /* prints
21 Original size: 800
22 */
23 echo "Compressed size: ". strlen($compressed)."\n";
24 /* prints
25 Compressed size: 418
26 */
27 // getting it back
28 $original = gzuncompress($compressed);
我們能夠壓縮近 50% 。另外 gzencode() 和 gzdecode() 可以達成類似的結果,但通過的是不同的壓縮演算法。
9. register_shutdown_function
有一個函數叫 register_shutdown_function(),可以讓你在擁有執行一些代碼許可權之前,完成指令碼的運行。
試想一下,你想捕捉到你指令碼執行至結束時一些基準的統計資料,如一共用了多少時間來執行:
view sourceprint?1 // capture the start time
2 $start_time = microtime(true);
3 // do some stuff
4 // ...
5 // display how long the script took
6 echo "execution took: ".
7 (microtime(true) - $start_time).
8 " seconds.";
起初覺得這些似乎是微不足道的。你只要添加代碼放在底部,它運行指令碼之前完成。不過,在指令碼程式其中你調用了 exit() 函數,那麼該段代碼將不被執行。此外,如果有一個致命的錯誤,或者該指令碼由使用者終止(就是按瀏覽器上面的停止按鈕),再次重新整理頁面也無法被運行。
當您使用 register_shutdown_function(),你的代碼將沒有理由被迫停止:
view sourceprint?01 $start_time = microtime(true);
02 register_shutdown_function('my_shutdown');
03 // do some stuff
04 // ...
05 function my_shutdown() {
06 global $start_time;
07 echo "execution took: ".
08 (microtime(true) - $start_time).
09 " seconds.";