首頁 > 後端開發 > php教程 > PHP學習寶典-第八章(二)

PHP學習寶典-第八章(二)

黄舟
發布: 2023-03-04 07:14:01
原創
962 人瀏覽過

進價函數技巧

現在我們來看看函數的一些更神奇的屬性,其中包括使用可變參數個數的方法、讓函數能夠修改傳入變數的方法,以及讓函數成為資料使用的法方。

這一節的內容是本章最具挑戰性的一節,它只適合具有冒險精神、求知欲極強或經驗豐富的程式設計師。

可變參數個數

在依據情況呼叫傳入函數時,知道實際參數數量是很有用的,在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”,


$desc = “vast metropolis”,


$desc = “vast metropolis”,


$desc = “vast metropolis”,


$desc = "vast metropolis",


dozens”,

$of_what = “costumed villains”)

{

print(“$city is a $desc filled with

$how_many of $of_what.” );

tour_guide(「Chicago」);

tour_guide(「Chicago」,「wonderful city」);

tour_guide(「Chicago」,「wonderful city",ag “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 willar. 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 offul city filled with teeming millions of gruff people whit hearts of gold and hard-lo 的主要參數。限制是,實際參數到形式參數的匹配是由兩者的依序比對決定的,先到先服務。因而不能亂用預設參數的設定,以致最後出一堆問題而不自知。

用陣列取代多個參數

如果對多個參數的彈性不怎麼滿意,可以使用陣列來當成溝通手段,這樣可繞過整個參數計數問題。

下面的例子就是使用這個策略,另外還用了幾個小技巧,如三元運算子(在第七章中介紹過)和關聯陣列(在第六章中提不定期,在第十一章才會全面解說):

function tour_brochure($info_array)

{

$city = 

IsSet ($info_array[?city?])?


IsSet ($info_array[?city?])?


IsSet ($info_array[?city?])?

? 」;

$desc = 

IsSet ($info_array[?city?])?

$info_array[?desc?]:「great metroprlis」;

$howymany =[vall; ])?

$info_array[?how_many?]:「dozens」;

$of_what

IsSet ($info_array[?of_what?])?

$info_array[cosff;
print(“$city is a $desc filled with

$how_many of $of_what.”);

}

這個函式檢查將傳入的數位參數與特定字串的四位數不同的值進行比較,使用三元條件運算子“?”,區域變數被指定為傳入的值(如果已經儲存在陣列中),不然就是以預設值指定。現在,我們嘗試用兩個不同的陣列呼叫這個函式:

tur_brochure(array()); //空陣列

$tour_info = 

aray(?city?=>?Cozumel?,

?desc ?=>?destination getaway?,

'of_what'= >'sandy beaches');

tur_brochure($tour_info);

在這個例子中,我們首先用空陣列(對應於無參數)呼叫然後用一個陣列來呼叫它,陣列中儲存了四種可能關聯值中的三種。其瀏覽器輸出為:

Gotham City is a great metropolis filled with dozens of costumed villains.🎜🎜Cozumel is a destination getaway filled with dozens of sbeaches.🎜🎜在兩種情況下,「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
{

$local_array[$counter] =$nc_oha; counter + 1;

}

rturn($local_array);

}

fnction args_as_array_2()

{e式使用了func_get_arg()來擷取每個單獨的參數,並使用func_num_args()的結果來給迴圈定出界限,因此檢索的參數不會比實際傳入的多。每個參都被存放到陣列中,然後把這個陣列傳回。把這樣的參數包裝起來實際上已經由func_get_arps()完成了,因此該函數的第二個版本就很簡短了。

這裡是另一個例子,我們重寫前面的tour_guide()函式,它使用了多個參數函數來取代預設參數:

fnction tour_guide_2()

{

$num_args=func_num_snums(argsnum_sargs(Sargs$num_args=func ;

$city = $num_args > 0 ?

fnc_get_arg(0):「Gotham City」;

$desc = $num_args >1 ?

$desc = $num_args > 1 ?
「great metropolis」;

$how_many = $num_args > 2 ?

fnc_get_arg(2):「dozens」;

$of_what = $num_args > 3 ?

pint(“$city is a $desc filled with

$how_many of $of_what. ”);

}

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
de( 「Negative numbers are imaginary」);

$return_result = 0;

wile($numl >$num2)

{

$numl = $numl – 1;

{

$numl = $numl – 1;
1; }

rturn($return_result);

}

$first_op = 493;

$second_op = 355;

$result1 = my_subtract($first_op,$second_op);

pint(“result1 is $result1”);

$result2 = my_subtract($first_op,$second_op);

Print(“result2 is $result2”);

,我們看到了執行同樣減法兩次所得的結果會是一樣:

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($owile($en($e)($e)a($e)a($e)a($eS)($e)a($e)a($a) = $num1 – 1;

$return_result = $return_result + 1;

}

rturn($return_result);

}

_$first_result);

}

_$first_opopopp; my _subtract_ref($first_op, $second_op);

pint(“result1 is $result1”);

$result2 = my_subtract_ref($first_op,$second_op); 」);

現在,如果像前在那樣執行同樣的減法呼叫,會得到這樣的輸出:

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”);

$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 ”);

Prnt(“$alias_2 is $name_2”);

上面的程式碼會得到這樣的瀏覽器輸出:

The Red Baron is Manfred von Richtofen

Scarlet Pimpernel

可變函數名稱

PHP中的一個非常靈活的技巧就是用變數來取代使用者定義函數的位置。也就是說,在程式碼中不必鍵入字面上的函數名稱,而是可以鍵入以「&」符號開頭的變數,執行時實際呼叫的函數取決於指定給該變數的字串。在某種意義上,這就允許把函數當成資料來使用。這個技巧對於進價C語言程式設計師來說可能很熟悉,對於任何種類的Lisp語言(如Scheme或Common Lisp)的初學者來說也是如此。

例如,下面的兩個函數呼叫完全是相等的:

function customized_greeting()

{

print(“You are being greeted in a customized way
print(“You are being greeted in a customized way
customized_greeting();

$my_greeting = 'customized_greeting';

$my_greeting();

上面的程式碼產生相同的輸出:

Youare being greeted in aben 起customized way !

因為函數名稱就是字串,所以也可以當成函數的參數,或是當成函數結果來傳回。

延伸擴充範例+

讓我們來看看使用函數的一個更進階特性會遇到什麼樣的麻煩,包括使用函數名稱為函數參數。

範例8-1這個例子所顯示的是函數的一個延伸的擴充範例,該函數完成實行替換密碼的功能,這是一種最原始的密碼系統,用字母表中的一人字母替換另一個字母,以弄亂顯示的資訊。

下面的程式碼算是本書到目前為止所示範的任何程式碼中比較長的,也更進階。對於不想了解它細節的人來說,可以跳過這段程式碼。

範例8-1 密置換

/*第一部分:密碼演算和工具函*/

function add 1($num)

{

return($num+ 1)%26);
return($num+ 1)%26);
return($num+ 1)%26);
return($num+ 1)%26);
return($num+ 1)%26);
}

function sub_1($num)

{

return(($num+ 25)% 26);

}

function swap 26);

}

function swap 2%($) = 0)

return($num+ 1);

else

return($num - 1);

}

函數交換26($num)


{

return(25 -)

函數小寫字母($char string)

{

return(ord($char string) >=ord('a'))&&

(ord(&char string)
}

函數大寫字母($char string)

{

return((ord($char string) >=ord('A'))&&

(ord($char string)
}

/*第二個:字母密碼函數*/

函數字母密碼($char string, $code func)

{

if !(大寫字母( $char string)||

小寫字母($char string)))

return($char string);

if(大寫字母($char string))

$base num = ord ('A') ;

else

$base num = ord($char string) –

$base num);

return(chr($base num + 

($code func ($char num ) )));

}

/*第三自訂:主要字串密碼函數*/

function string cipher($message,$cipher func)

{

$coded message = ”
$訊息長度= strlen($message);

for($index= 0;

$index
$index++)

$編碼訊息.=

$index++)

$編碼訊息.=字母密碼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。變成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 = 「我的秘密訊息是ABCDEFG」;

Print(「原始訊息是:$orinal」);

$coding_array = array('add_1',

'sub_1,

'swap_2',

'swap_26');

For($count = 0;

_$count
String_cipher($original,$code);

Print(“$code編碼為:$coded_message
”);

}

這些測試程式碼使用預先定義的四個編碼字母隱藏函數,字母編碼隱藏函數,將它們放在陣列中,然後迴圈巡查陣列,編碼$原始影像,並輸出顯示編碼後的版本。編碼是:Nz tfdsfu nfttbhf jt BCDEFGH

sub_1 編碼是:Lx rdbqfs nfttbhf jt BADCFRH

swap_2 編碼是:Nz tfdqfs nfttbhf jt BADC
swap_2 編碼是:Nz tfdqfs

我們可以把這個函數做為資料的方法再深入一步,寫一個給序列中的訊息應用多個密碼的函比。
/* 先取得回應定值,然後取代編輯碼函數訊息名稱找任意選項。在前一結果上應用每道編碼函數,然後回傳其結果。 */

$argc = func_num_args();

$coded = $message;

For ($count = 1 ;$count
{Nargs
_args ;

$coded = 

String_cipher($coded,

$function_name);

}

Return($coded);

}

Return($coded);

}

Return($coded);
是對應於密碼函數的任數目的名稱。被編碼的訊息是讓訊息套用第一個編碼函數的結果,然後再讓結果套用第二個編碼函數,以此類推。我們可以透過使用預先定義的字母編碼函數的各種組合方式對它進行測試。

$tricky = 

Chained_code($original,

'add_1''swap_26',

'add_1''swap_2');
icky
(“icky en $easy = 

Chained_code($original,

'add_1','swap_26',

'swap_','sub_1',

'add_1', 'swap_','sub_1',

'add_1', 'swapap_2,'sub_1',

'add_1', 'swapap''2,' );

Print(“Easy encoded version is $easy”);

其結果為:

Tricky encoded version is Ma guwjh muggysug YXWXUVSare on XUV
正你所看到期的,「tricky」訊息傳遞者按碼前是前程式碼的組合形式,但沒有確切對應任何一種單獨的編碼函數。而「easy」編碼是這些函數較複雜的組合形式,產生的結果就是最初的訊息…沒有任何改變! (這並不是因為密鑰代碼無效,我們只是想讓讀者弄清楚為什麼這種特定的編輯函數序列能夠再次回到原來開始的訊息。)

這個小小的密碼script所示範圍的目的是想讓你了解,雖然密碼程式稍微複雜了些,但由於PHP支援使用函數名稱當成函數參數來用,使得這件事情變得相當簡單。

摘要

大多數的PHP功能都存在於大量的內建函數中,它們是由PHP的開放原始碼開發團隊所提供的。每個函數在http://www.php.net的線上手冊中都應該有說明(雖然有些很短)。

你也可以寫屬於自己的函式,然後函數可以與內建函式以相同的方式取用。函數以簡單的C語言風格的語法來寫,如下所示:

Function my_function ($argl,$arg2,…)

{

Statement1;

Statement2; );

}

使用者定義的函數可以使用任何PHP型別的參數來配合,另外也可以傳回任何型別的值。且不需要針對參數和回傳值的型別進行宣告。

在PHP4中,函數定義和函數呼叫的次數沒有區別,只要呼叫的每個函數曾經定義就可以了。對於單獨的函數宣告或原型設計是不需要的。函數內指定的變數會限制在該函數區域中,除非用了global宣告。區域變數可以宣告為static,這意謂它們在函數呼叫之間可保留自己的值。

使用者定義函數的預設動作行為是「按值呼叫(call_by_reference)」,這是指該函數在運作上使用的是參數的副本,因此不能在函數呼叫中修改原始變數。透過在參數前加一個“&”,可以強制進行“按引呼叫(call-by-reference)”,不管是在定義方,或在呼叫方都可配合使用。 PHP提供了多種途徑讓函數所帶的參數數量變化變動。最後,要呼叫的函數可以在執行時期確定,用一個字符串變數取代使用者定義函數的名字,那就允許把函數當成資料來對待,並讓它在其它函數之間來回傳遞。

 以上就是PHP學習寶典-第八章(二)的內容,更多相關內容請關注PHP中文網(www.php.cn)!


相關標籤:
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板