php开发宝典例8.2,PHP学习宝典-第八章(二)
進價函式技巧
現在我們來看看函式的一些更神奇的屬性,其中包括使用可變參數個數的方法、讓函式能夠修改傳入變數的方法,以及讓函式成為資料使用的法方。
這一節的內容是本章最具挑戰性的一節,它只適合具有冒險精神、求知欲極強或經驗豐富的程序設計師。
可變參數個數
在依據情況呼叫傳入函式時,知道實際參數數量是很有用的,在PHP中有三種可能的方式處理,其中一個只能在PHP4使用:
1. 定義帶有預設參數的函式,當函式在呼叫中遺漏任何參數時,它都會用預設值來代替,不會顯示警告資訊。
2. 使用陣列參數存放這些值,由呼叫的程序碼中負責包裝這個陣列,函式本體必須適當地將其中的資料分離。
3. 使用PHP4中的可變參數函式(func_num_args()、func_get_arg()和 func_get_args())。
預設參數
為了定義帶有預設參數的函式,只需把形式參數變成指定運算式即可。如果實際呼叫時的參數比定義時的形式參數少,PHP會拿形式參數和實際參數進行比對匹配,直到用完為止,然后就使用預設的指定來填滿其余參數。
例如,下面的函式中的變數都有是用預設值定義的:
function tour_guide($city = “Gotham City”,
$desc = “vast metropolis”,
$how_many = “dozens”,
$of_what = “costumed villains”)
{
print(“$city is a $desc filled with
$how_many of $of_what.< BR >”);
}
tour_guide();
tour_guide(“Chicago”);
tour_guide(“Chicago”,“wonderful city”);
tour_guide(“Chicago”,“wonderful city”,
“teeming millions”);
tour_guide(“Chicago”,“wonderful city”,
“teeming millions”,
“gruff people with hearts of
gold and hard-luck stories to tell”);
瀏覽器會輸出類似下面的結果,句中的換行符號由所用瀏覽器決定:
Gotham City is a great metropolis filled with dozens of costumed villains.
Chicago is a great metropolis filled with dozens of costumed villains.
Chicago is a wonderful city filled with dozens of costumed villains.
Chicago is a wonderful city filled with teeming millions of costumed villains.
Chicago is a wonderful city filled with teeming millions of gruff people whit hearts of gold and hard-luck stories to tell.
預設參數的主要限制是,實際參數到形式參數的匹配是由兩者的依序比對確定的,先到先服務。因而不能亂用預設參數的設定,以致最后出一堆問題而不自知。
用陣列替代多個參數
如果對多個參數的彈性不怎么滿意,可以使用陣列來當成溝通手段,這樣可繞過整個參數計數問題。
下面的例子就是使用這個策略,另外還用了幾個小技巧,如三元運算子(在第七章中介紹過)和關聯陣列(在第六章中提不定期,在第十一章中才會全面講解):
function tour_brochure($info_array)
{
$city =
IsSet ($info_array[?city?])?
$info_array[?city?]:“Gotham City”;
$desc =
IsSet ($info_array[?city?])?
$info_array[?desc?]:“great metroprlis”;
$how_many =
IsSet ($info_array[?how_many?])?
$info_array[?how_many?]:“dozens”;
$of_what
IsSet ($info_array[?of_what?])?
$info_array[?of_what?]:“costumed villains”;
print(“$city is a $desc filled with
$how_many of $of_what.< BR >”);
}
這個函式檢查將傳入的陣列參數與特定字符串相隔的四種不同的值進行比較,使用三元條件運算子「?」,區域變數被指定為傳入的值(如果已經被儲存在陣列中),不然就是以預設值指定?,F在,我們嘗試用兩個不同的陣列呼叫這個函式:
tur_brochure(array()); //空陣列
$tour_info =
aray(?city?=>?Cozumel?,
?desc?=>?destination getaway?,
‘of_what’= >‘sandy beaches’);
tur_brochure($tour_info);
在這個例子中,我們首先用空陣列(對應于無參數)呼叫tour_brochure,然后用一個陣列來呼叫它,陣列中儲存了四種可能關聯值中的三種。其瀏覽器輸出為:
Gotham City is a great metropolis filled with dozens of costumed villains.
Cozumel is a destination getaway filled with dozens of sandy beaches.
在兩種情況下,「dozens」數量是預設的,因為兩陣列都沒有任何內容儲存在「how_many」關聯部份中。
在PHP4中使用多重參數
最后,PHP4提供了一些函式,可在函式本體內重新獲得參數的個數和值,這些函式是:
fnc_num_args()不帶參數,傳回呼叫該函式時傳入的參數個數。
fnc_get_arg()帶一個整數參數n,傳回該函式呼叫的第n個參數。參數計數從0開始。
fnc_get_args()不帶參數,傳回一個陣列,其中包含該函式呼叫的所有參數,陣列索引從0開始。
如果在函式本體外呼叫它們,這三個函式皆會丟出警告訊息,如果呼叫時所用的索引高于傳入的最后的參數索引,func_get_arg()也會丟出警告。
如果使用者的函式會用到這些函式功能進行參數的解碼,可以充分利用這里提到的關于函式呼叫,PHP不會因為實際參數比定義中的形式參數個數多而有所報怨。使用者可以定義不帶參數的函式,然后使用這個函式來對比匹配任何實際傳入的函式。
舉例來說,請思考下面的兩個函式實例,這些函式都傳回一個被傳入的參數陣列:
fnction args_as_array_1()
{
$arg_count = func_num_args();
$counter = 0;
$local_array = array();
wile($counter < $arg_count)
{
$local_array[$counter] =
fnc_get_arg($ary_counter);
$counter = $counter + 1;
}
rturn($local_array);
}
fnction args_as_array_2()
{
rtun(func_get_args());
}
第一個累贅的函式使用了func_get_arg()來擷取每個單獨的參數,并使用func_num_args()的結果來給回圈定出界限,因此檢索的參數不會比實際傳入的多。每個參都被存放到陣列中,然后把這個陣列傳回。把這樣的參數包裝起來實際上已經由func_get_arps()完成了,因此該函式的第二個版本就很簡短了。
這里是另外一個例子,我們重寫前面的tour_guide()函式,它使用了多個參數函式來替換預設參數:
fnction tour_guide_2()
{
$num_args=func_num_args();
$city = $num_args > 0 ?
fnc_get_arg(0):“Gotham City”;
$desc = $num_args >1 ?
$desc = $num_args > 1 ?
fnc_get_arg(1):“great metropolis”;
$how_many = $num_args > 2 ?
fnc_get_arg(2):“dozens”;
$of_what = $num_args > 3 ?
fnc_get_arg(3):“costumed villains”;
pint(“$city is a $desc filled with
$how_many of $of_what. < BR >”);
}
tur_guide2();
上面的程序碼與預設參數形的程序碼作用和效果相同,而且受到同樣的限制。參數按照位置傳入,因此沒有辦法用別的內容來替換「costumed villains」,只有用「Gotham City」為預設值。
按值呼叫(call-by-value)vs .按參引呼叫(call-by-reference)
PHP中使用者定義函式的預設動作是「按值呼叫(call-by-value傳值呼叫)」,這意味著當把變數傳遞給函式呼叫時,PHP幫變數值制作一份副本并傳給函式。因此,無論函式做什么,它都不能更改出現在函式呼叫中的實際變數。這種行為雖有好處,但也有壞處。當我們只想利用函式的傳回值時,這當然是很好的方式,但如果修改傳入的變數是實際目標,這樣反而會有所妨礙。
下面會示范一個相當沒有效率的減法例子的實作來按值呼叫的應用:
fnction my_subtract($numl,$num2)
{
i ($numl < $num2)
de(“Negative numbers are imaginary”);
$return_result = 0;
wile($numl >$num2)
{
$numl = $numl – 1;
$return_result = $return_result + 1;
}
rturn($return_result);
}
$first_op = 493;
$second_op = 355;
$result1 = my_subtract($first_op,$second_op);
pint(“result1 is $result1< BR >”);
$result2 = my_subtract($first_op,$second_op);
Print(“result2 is $result2< BR >”);
真好,我們看到了執行同樣減法兩次所得的結果會是一樣:
rsult1 is 138
rsult2 is 138
即使my_subtract改變了它的形式參數$numl的值,還是會得到這樣的結果,$numl變數只存放實際參數$first_op中值的副本而已,因此$first_op不會受到影響。
按照引呼叫(call-by-reference)
PHP提供了兩種不同方式讓函式在定義中,或者在函式呼叫中,更有能力來修改參數,也稱為傳址呼叫。
如果要定義一個直接對傳入變數進行操作的函式,可以在定義中時在形式參數前面加一個「&」符號,如下所示:
fnction my_subtract_ref(&$numl,&$num2)
{
i($numl-
de(“Negative numbers are imaginary”);
$return_result = 0;
wile($num1 >$num2)
{
$numl = $num1 – 1;
$return_result = $return_result + 1;
}
rturn($return_result);
}
$first_op = 493;
$second_op = 355;
$result1 = my _subtract_ref($first_op, $second_op);
pint(“result1 is $result1< BR >”);
$result2 = my_subtract_ref($first_op,$second_op);
pint(“result2 is $result2< BR >”);
現在,如果像前在那樣執行同樣的減法呼叫,會得到這樣的輸出:
rsult1 is 138
rsult1 is 0
這是因為形式參數$numl和實際參數$first_op所指的內容相同,修改一個就等于修改了另一個。
還可以透過在實際參數前加上「&」符號,強制一個函式按參此傳遞參數(這是一個漸遭淘汰的功能,而且可能在未來的PHP版本中被移除)。也就是說,可以使用最初的按值呼叫函式得到按參引的動作,如下所示:
$first_op = 493;
$second_op = 355;
$result1 = my_subtract(&$first_op,&$second_op);
Print(“result1 is $result1< BR >”);
$result2= my_subtract(&$first_op,&$second_op);
Print(“result2 is $result2< BR >”);
這次又得到了下面的結果:
rsult1 is 138
rsult1 is 0
關于PHP4,變數參引也能夠用在函式呼叫的外面。一般來說,將一個變數參引(&$varname)指定給變數會使這兩種變數互相成為彼此的別名,
(也就是分身),而不是具有同樣值的兩個不同變數。例如:
$name_1 = “Manfred von Richtofen”;
$name_2 = “Percy Blakeney”;
$alias_1 = $name_1; //變數具有相同值
$alias_2=&$name_2;//變數相同
$alias_1 = “The Red Baron”;//實際名稱沒有改變
$alias_2 = “The Scarlet Pimpernel”;//無論是什么都已經無關緊要了
Prnt(“$alias_1 is $name_1< BR> ”);
Prnt(“$alias_2 is $name_2< BR >”);
上面的程序碼會得到這樣的瀏覽器輸出:
The Red Baron is Manfred von Richtofen
The Scarlet Pimpernel is The Scarlet Pimpernel
可變函式名稱
PHP中的一個非常靈活的技巧就是用變數來代替使用者定義函式的位置。也就是說,在程序碼中不必鍵入字面上的函式名稱,而是可以鍵入以「&」符號開頭的變數,在執行時實際呼叫的函式取決于指定給該變數的字符串。在某種意義上,這就允許把函式當成資料來使用。這種技巧對于進價C語言程序設計師來說可能很熟悉,對于任何種類的Lisp語言(如Scheme或Common Lisp)的初學者來說也是如此。
例如,下面的兩個函式呼叫完全是相等的:
function customized_greeting()
{
print(“You are being greeted in a customized way !< BR >”);
}
customized_greeting();
$my_greeting = ‘customized_greeting’;
$my_greeting();
上面的程序碼產生同樣的輸出:
You are being greeted in a customized way !
You are being greeted in a customized way !
因為函式名稱就是字符串,所以也可以當成函式的參數,或者當成函式結果來傳回。
延伸擴充范例+
讓我們來看看使用函式的一個更進階特性會遇到什么樣的麻煩,包括使用函式名稱為函式參數。
范例8-1這個例子所顯示的是函式的一個延伸的擴充范例,該函式完成實作替換密碼的功能,這是一種最原始的密碼系統,用字母表中的一人字母替換另一個字母,以弄亂顯示的資訊。
下面的程序碼算是本書到目前為止所示范的任何程序碼中比較長的,也更進階。對于不想了解它細節的人來說,可以跳過這段程序碼。
范例 8-1 密 置換
/*第一部份:密碼演算和工具函*/
function add 1($num)
{
return(($num+ 1)%26);
}
function sub_1($num)
{
return(($num+ 25)% 26);
}
function swap 2 ($num)
{
if($num % 2 == 0)
return($num+ 1);
else
return($num - 1);
}
function swap 26($num)
{
return(25 - $num);
}
function lower letter($char string)
{
return(ord($char string) >=ord(‘a’))&&
(ord(&char string)< =ord(‘z’)));
}
function upper letter($char string)
{
return((ord($char string) >=ord(‘A’))&&
(ord($char string)< =ord(‘z’)));
}
/*第二部份:letter cipher函式 */
function letter cipher ($char string, $code func)
{
if!(upper letter($char string)||
lower letter ($char string)))
return($char string);
if(upper leter($char string))
$base num = ord(‘A’);
else
$base num = ord($char string) –
$base num);
return(chr($base num +
($code func ($char num )
% 26)));
}
/*第三部份:主要string cipher 函式 */
function string cipher($message,$cipher func)
{
$coded message = ””;
$message length = strlen($message);
for($index= 0;
$index < $message length;
$index++)
$coded message .=
letter cipher ($message[$index],$cipher func);
return($coded message);
}
范例8-1共有三個部分。在第一部份中,我們定義了幾個對數字0—25進行簡單數字運算的函式,這些數字代表密碼程序中的字母A—Z。函式add_1把給它的數字加1,以「26」為模數(僅意味著26以及超過26的數字會“繞回”到開頭從「0」開始。0變成1 、 1變成2 、…、25變成0。Sub_1則是沿另一個方向轉換數字,透過加上25(在這種模數算法中就等于減1),25變成24 、 24變成23 、… 、0變成25。Swap_2則是以成對的方式置換數字的位置(0到1 、1到0 、 2到3 、 3到2…等等),swap_26則把較高的數字和較低的數字地行對調置換(25到0 、0到25 、 24到1 、1到24…等等)。
所有這些函式都算是這個簡易密碼程序的基礎。最后還有兩個公用程序函式,用以測試字符是大寫還是小寫字母。
第二部分就是個letter_cipher()函式,并該函式的工作是取得第一部分中的一個算術函式,然后應用它來對簡單字母進行編碼。該函式會先測試它處理的字符串(其中只有單元一字符)是否為字母;如果不是,則按原樣傳回。如果字符是個字母,則可使用。Ord()的功用是將其轉化為數字,然后減支適當的字母(a或A),以把數字限定到0—25之間。一旦位于這個范圍內,就可以應用其名字以字符串方式傳入的密碼函式中,然后再把數字轉換成字母,最后傳回它。
最后,第三部分是string_cipher()函式,該函式帶有一個字符串訊息,還有一個密碼函式,它傳回的是一個新字符串值,其值為透過函式進行編碼的內容。這里用到一兩個以前沒見到的功能(其中包括字符串連接運算子「.=」,在第十章中會提到),這個函式從訊息字符串的字母逐一進行處理,建構出新字符串,并用新字母是對對照舊字母的數字表示應用了$cipher_func得到的結果,到這里你大概了解這些足夠了。
下面,我們編寫一些程序碼測試string_cipher();
$originak = “My secret message is ABCDEFG”;
Print(“Original message is :$orginal< BR >”);
$coding_array = array(‘add_1’,
‘sub_1,
‘swap_2’,
‘swap_26’);
For($count = 0;
$count < sizeof($coding_array);
$coded_message =
String_cipher($original,$code);
Print(“$code encoding is :$coded_message< BR >”);
}
這些測試程序碼使用了預先定義的四個字母編碼函式,把它們隱藏在一個陣列中,然后回圈遍巡該陣列,編碼$original訊息,并輸出顯示編碼后的版本。瀏覽器輸出如下所示:
original message is: My secret message is ABCDEFG
add_1 encoding is :Nz tfdsfu nfttbhf jt BCDEFGH
sub_1 encoding is :Lx rdbqfs nfttbhf jt BADCFRH
swap_2 encoding is :Nz tfdqfs nfttbhf jt BADCFEH
swap_26 encoding is : Nb hvxivg nvhhztv rh ZYXWVUT
我們可以把這個函式做為資料的方法再深入一步,編寫一個給序列中的訊息應用多個密碼的函比。這個函式也使用了PHP4的可變參數型函式:
Function chained_code ($message)
{
/* 先取得反映定訊息,然后替編輯碼函式名稱找個任意數目。
在前一結果上應用每道編碼函式,然后回傳其結果。 */
$argc = func_num_args();
$coded = $message;
For ($count = 1 ;$count
{
$function_name = func_get_arg($count);
$coded =
String_cipher($coded,
$function_name);
}
Return($coded);
}
Chained_code()的第一個參數應該是個訊息字符串,后面是對應于密碼函式的任意數目的名稱。被編碼的訊息是讓訊息套用第一個編碼函式的結果,然后再讓結果套用第二個編碼函式,以此類推。我們可以透過使用預先定義的字母編碼函式的各種組合方式對它進行測試。
$tricky =
Chained_code($original,
‘add_1’‘swap_26’,
‘add_1’‘swap_2’);
Print(“Tricky encoded version is $tricky< BR >”);
$easy =
Chained_code($original,
‘add_1’,‘swap_26’,
‘swap_’,‘sub_1’,
‘add_1’, ‘swap_2,’
‘swap_26,’‘sub_1,’);
Print(“Easy encoded version is $easy< BR >”);
其結果為:
Tricky encoded version is Ma guwjh muggysu qg YXWXUVS
Easy encoded version is My secret message is ABCDEFG
正你所看到期的,「tricky」訊息編者按碼前是前程序碼的組合形式,但沒有確切對應任何一種單獨的編碼函式。而「easy」編碼是這些函式更復雜的組合形式,產生的結果就是最初的訊息……沒有任何改變!(這并不是因為密鑰程式碼無效,我們只是想讓讀者弄明白為什么這種特定的編輯函式序列能夠再次回到原來開始的訊息。)
這個小小的密碼script所示范圍的目的是想讓你了解,雖然密碼程式稍微復雜了些,但由于PHP支援使用函式名稱當成函式參數來用,使得這件事情就變得相當簡單。
摘要
大多數的PHP功能都存在于大量的內建函式中,它們是由PHP的開放原始碼開發團隊所提供的。每個函式在http://www.php.net的線上手冊中都應該有說明(雖然有些很簡短)。
你也可以編寫屬于自己的函式,然后該函式可以與內建函式以同樣的方式取用。函式用簡單的C語言風格的語法來編寫,如下所示:
Function my_function ($argl,$arg2,…)
{
Statement1;
Statement2;
…
Return($value);
}
使用者定義的函式可以使用任何PHP型別的參數配合,另外也可以傳回任何型別的值。且不需要針對參數和回傳值的型別進行宣告。
在PHP4中,函式定義和函式呼叫的次數沒有區別,只要呼叫的每個函式曾經定義就可以了。對于單獨的函式宣告或原型設計是不需要的。函式內指定的變數會限制在該函式區域中,除非用了global宣告。區域變數可以宣告為static,這意謂著它們在函式呼叫之間可保留自己的值。
使用者定義函式的預設動作行為是「按值呼叫(call_by_reference)」,這是指該函式在運作上使用的是參數的副本,因此不能在函式呼叫中修改原始變數。透過在參數前加一個「&」,可以強制進行「按引呼叫(call-by-reference)」,不管是在定義方,或者在呼叫方都可配合使用。PHP提供了多種途徑讓函式所帶的參數數量可變動。最后,要呼叫的函式可以在執行時期確定,用一個字串變數替代使用者定義函式的名字,那就允許把函式當成資料來對待,并讓它在其它函式之間來回傳遞。
以上就是PHP學習寶典-第八章(二)的內容,更多相關內容請關注PHP中文網(www.php.cn)!
相關標簽:PHP學習
本文原創發布php中文網,轉載請注明出處,感謝您的尊重!
相關文章
相關視頻
總結
以上是生活随笔為你收集整理的php开发宝典例8.2,PHP学习宝典-第八章(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 通过PHP 获取身份证相关信息 获取生肖
- 下一篇: 码云图床php,PHP 脚本实现 Mar