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