- PHP動態(tài)網(wǎng)站開發(fā)實踐教程
- 盧欣欣 李靖主編
- 3748字
- 2021-09-17 17:55:57
4.2 自定義函數(shù)
自定義函數(shù)就是程序員根據(jù)實際功能需求定義的函數(shù),通常將某段實現(xiàn)特定功能的代碼定義成一個函數(shù),寫在一個獨立的代碼塊中,在需要使用的時候單獨調(diào)用,可以大大提高程序的開發(fā)效率。
4.2.1 函數(shù)的定義
在PHP中,自定義函數(shù)使用function來定義,其語法格式如下。

說明:
1)function:函數(shù)定義時必須使用的關(guān)鍵字。
2)函數(shù)名:定義的函數(shù)名稱,像變量名一樣,必須符合標(biāo)識符的命名規(guī)則,只是不需要以“$”開頭。
3)參數(shù)1,參數(shù)2,…,參數(shù)n:外界傳遞給函數(shù)的值,根據(jù)實際情況,可以有參數(shù),也可以沒有參數(shù),當(dāng)有多個參數(shù)時,中間以“,”隔開。
4)函數(shù)體:函數(shù)定義的主體,是函數(shù)功能的實現(xiàn)。
5)返回值:根據(jù)函數(shù)實現(xiàn)的功能,若要得到一個結(jié)果,即是函數(shù)的返回值,使用return關(guān)鍵字將需要返回的數(shù)據(jù)傳遞給調(diào)用者。如果不需要返回結(jié)果,則可以沒有return語句。
另外,函數(shù)名的命名規(guī)則如下:
1)有效的函數(shù)名以字母或下劃線開頭,后面跟字母、數(shù)字或下劃線。
2)函數(shù)名不能與關(guān)鍵字同名,如empty、break等。
3)函數(shù)名不區(qū)分大小寫,這和變量命名不一樣。例如,Output()和output()是指同一個函數(shù),但仍建議使用時的函數(shù)名和定義時的函數(shù)名大小寫保持一致。
4.2.2 函數(shù)的調(diào)用
要執(zhí)行函數(shù)內(nèi)部的代碼,就需要調(diào)用函數(shù)。函數(shù)調(diào)用的語法格式如下。

其中,“參數(shù)1,參數(shù)2…”表示參數(shù)列表,是可選擇的。下面通過示例來演示函數(shù)的定義和調(diào)用。
【例4-1】無參函數(shù)調(diào)用。

上述代碼定義了函數(shù)output(),它是無參函數(shù),函數(shù)的功能是輸出“?????”,通過調(diào)用output()函數(shù),運行結(jié)果如下:

【例4-2】有參函數(shù)調(diào)用。

上述代碼定義了函數(shù)introduce(),它是有參函數(shù),參數(shù)是$name,函數(shù)的功能是輸出姓名,通過調(diào)用函數(shù),參數(shù)“張三”傳給$name,運行結(jié)果如下:

4.2.3 函數(shù)的返回值
當(dāng)調(diào)用函數(shù)時,有時需要得到處理結(jié)果,這個結(jié)果稱為返回值。在PHP中,使用return語句將結(jié)果返回給調(diào)用者,return語句后緊跟的返回值可以是變量、常量、數(shù)組或表達(dá)式等。下面通過一個示例來更好地理解return語句的使用。
【例4-3】返回值的使用。

運行結(jié)果如下:

上述代碼中,定義了函數(shù)area(),用來求長方形的面積,通過語句“return$s”將面積返回。return語句不能一次返回多個值,只能返回一個值,并且return語句后的代碼將不會被執(zhí)行。
當(dāng)return語句要返回多個值時,可以在函數(shù)中定義一個數(shù)組,將多個值存儲到數(shù)組中,然后通過return語句將數(shù)組返回。
【例4-4】分離各位數(shù)字。

運行結(jié)果:

4.2.4 函數(shù)的參數(shù)

4.2.4 函數(shù)的參數(shù)
在函數(shù)調(diào)用時,若需要向函數(shù)傳遞參數(shù),調(diào)用函數(shù)時的參數(shù)稱為實參,定義函數(shù)時的參數(shù)稱為形參。函數(shù)參數(shù)傳遞有值傳遞、引用傳遞和默認(rèn)值三種方式,下面對這三種方式進行詳細(xì)介紹。
1.值傳遞
函數(shù)默認(rèn)按值傳遞,相當(dāng)于將實參的值賦給了形參,在函數(shù)內(nèi)部改變形參的值,操作結(jié)果不會影響實參,也就是函數(shù)執(zhí)行后實參的值不變。
【例4-5】函數(shù)參數(shù)值傳遞。

運行結(jié)果:

為了更清晰地了解值傳遞,對上述代碼的執(zhí)行過程進行分析,具體如下。
1)函數(shù)只有被調(diào)用的時候才會執(zhí)行,因此程序段執(zhí)行的第一條語句是第7行,定義$age為9,PHP預(yù)處理器為$age分配一個存儲空間。
2)執(zhí)行第8行語句echo autoadd($age),此時autoadd()被調(diào)用,執(zhí)行第2行,實參$age將9傳遞給形參$n,PHP預(yù)處理器為$n分配一個空間。
3)執(zhí)行第4行代碼“$n=$n+1”,$n的值為10。
4)執(zhí)行第5行代碼“return$n”,將$n的值返回給調(diào)用函數(shù),此時將$n的值10返回給調(diào)用函數(shù)的第8行代碼,然后輸出結(jié)果10,此刻,函數(shù)調(diào)用結(jié)束,PHP預(yù)處理器收回$n的空間,$n消失。
5)執(zhí)行第9行代碼,輸出換行。
6)執(zhí)行第10行代碼,輸出$age的值,仍為9。
2.引用傳遞
引用傳遞就是將實參的內(nèi)存地址傳遞給形參,通過在函數(shù)的參數(shù)名前加上“&”來實現(xiàn)。實參和形參指向內(nèi)存中的同一個地址,函數(shù)執(zhí)行完后,實參的值會跟著形參的值發(fā)生變化。
【例4-6】函數(shù)參數(shù)引用傳遞。


運行結(jié)果:

為了更清晰地了解引用傳遞,對上述代碼的執(zhí)行過程進行分析,具體如下。
1)程序段執(zhí)行的第一條語句仍是第7行,定義$age為9,PHP預(yù)處理器為$age分配一個存儲空間。
2)執(zhí)行第8行語句echo autoadd($age),此時autoadd()被調(diào)用,執(zhí)行第2行,PHP預(yù)處理器為$n分配空間,由于這里是引用傳遞,相當(dāng)于傳地址,形參$n和實參$age都指向同一個變量9的地址,因此$n的值為9。
3)執(zhí)行第4行代碼“$n=$n+1”,形參$n修改地址中的值為10,由于$age也指向該地址,因此變量$age的值也變?yōu)?0。
4)執(zhí)行第5行代碼“return$n”,將$n的值返回給調(diào)用函數(shù),此時將$n的值10返回給調(diào)用函數(shù)的第8行代碼,然后輸出結(jié)果10。此刻,函數(shù)調(diào)用結(jié)束,PHP預(yù)處理器收回$n的空間,$n消失,但變量$age的值不會變,仍為10。
5)執(zhí)行第9行代碼,輸出換行。
6)執(zhí)行第10行代碼,輸出$age的值為10。
可見,使用值傳遞的方式為函數(shù)參數(shù)賦值,函數(shù)無法修改函數(shù)體外的變量值;若使用引用傳遞的方式為函數(shù)參數(shù)賦值,則函數(shù)可以修改函數(shù)體外的變量值。
3.默認(rèn)值
函數(shù)參數(shù)在設(shè)置時可以為其設(shè)置默認(rèn)值。當(dāng)調(diào)用者未傳遞該參數(shù)時,函數(shù)將使用默認(rèn)值進行操作。
【例4-7】設(shè)置函數(shù)參數(shù)默認(rèn)值。

運行結(jié)果:

上述代碼中,第8行、第10行分別調(diào)用了函數(shù)autoadd(),第1次調(diào)用時,實參$age和2傳遞給了形參$a和$b,通過函數(shù)計算$a的值為11。第2次調(diào)用時,實參只有一個參數(shù)$age,默認(rèn)第二個實參的值為函數(shù)中形參$b給的默認(rèn)值1,通過函數(shù)計算$a的值為10。因此第1次調(diào)用返回的結(jié)果為11,第2次調(diào)用返回的結(jié)果為10,由于是值傳遞,$age的值不受形參值的影響,輸出仍為9。需要注意的是,默認(rèn)值必須是常量表達(dá)式,不能是變量,任何默認(rèn)參數(shù)必須放在非默認(rèn)參數(shù)的右側(cè),否則函數(shù)將不會按照預(yù)期執(zhí)行。
在PHP7.0及以上的版本,自定義函數(shù)可以指定參數(shù)的具體數(shù)據(jù)類型,如例4-8所示。
【例4-8】弱類型參數(shù)類型。

運行結(jié)果:

上述代碼中,調(diào)用函數(shù)autoadd()時,傳入的參數(shù)不是自定義函數(shù)的參數(shù)類型,會自動將其轉(zhuǎn)換成int類型后進行操作,因此運行結(jié)果為10。
以上這種方式稱為弱類型參數(shù)設(shè)置,還有一種強類型的參數(shù),當(dāng)用戶輸入的數(shù)據(jù)類型不一致時,會給出錯誤提示,如例4-9所示。
【例4-9】強類型參數(shù)設(shè)置。

上述代碼中,“declare(strict_types=1);”用于設(shè)定一段代碼的執(zhí)行指令,表示當(dāng)前函數(shù)設(shè)置使用強類型參數(shù)設(shè)置。運行結(jié)果如下:

注意:在PHP 7.0及以上版本中,不僅可以設(shè)置函數(shù)的參數(shù)類型,還可以設(shè)置返回值的數(shù)據(jù)類型。當(dāng)返回值的數(shù)據(jù)類型和函數(shù)設(shè)置的返回類型不一致時,程序會報錯誤提示。
4.2.5 變量的作用域
所謂變量作用域,也就是變量的作用范圍,即變量起作用的程序代碼范圍。根據(jù)作用域的不同,可以分為局部變量和全局變量。
1.局部變量
在函數(shù)中定義的變量,稱為局部變量,其作用域是從變量定義處到函數(shù)結(jié)束;函數(shù)的形參變量等同于函數(shù)內(nèi)部定義的局部變量,它的作用域為整個函數(shù)內(nèi)部。
局部變量只能在作用域內(nèi)使用,在作用域外是不能使用的。需要注意的是,局部變量只有程序執(zhí)行到定義它的語句時才生成該變量,即分配內(nèi)存空間,一旦執(zhí)行流程退出該函數(shù),局部變量就會銷毀,釋放空間。
【例4-10】局部變量的使用。

運行結(jié)果如下:

2.全局變量
全局變量是定義在所有函數(shù)之外的變量,其作用域是從變量定義的位置開始到該變量所在程序的結(jié)尾處。全局變量不在某個函數(shù)內(nèi)部,其作用域內(nèi)的函數(shù)都可以訪問它。在P HP中,可以使用參數(shù)傳遞(前面介紹過,在此不再舉例)、global關(guān)鍵字、超全局變量$GLOBALS三種方式使用全局變量,如例4-11、例4-12所示。
【例4-11】global關(guān)鍵字的使用。

運行結(jié)果如下:

【例4-12】超全局變量$GLOBALS的使用。

運行結(jié)果如下:

4.2.6 函數(shù)的嵌套調(diào)用和遞歸調(diào)用
1. 嵌套調(diào)用
PHP中的各個函數(shù)是相互平行獨立的,沒有從屬關(guān)系,但是可以在一個函數(shù)內(nèi)調(diào)用另一個函數(shù),這種方式稱為函數(shù)的嵌套調(diào)用。例如,求三個數(shù)的最大值。
【例4-13】求三個數(shù)的最大值。

運行結(jié)果:

例4-13中所示,第2~5行代碼定義了一個求兩個數(shù)最大值的函數(shù)maxvalue(),第6行代碼對maxvalue函數(shù)進行嵌套調(diào)用,先調(diào)用maxvalue(6,2),求出最大值為6,然后第2次調(diào)用maxvalue()函數(shù),將上次的結(jié)果6作為函數(shù)的第二個參數(shù),執(zhí)行maxvalue(5,6),最后結(jié)果為6。可以看出,函數(shù)嵌套調(diào)用由內(nèi)向外執(zhí)行。
2.遞歸調(diào)用
所謂遞歸調(diào)用,是指在調(diào)用一個函數(shù)的過程中又直接或間接地調(diào)用該函數(shù)本身。但在編寫程序時,程序不可能無限地遞歸下去,必須要有遞歸結(jié)束的條件,而且每次遞歸都應(yīng)向結(jié)束條件邁進,直到滿足結(jié)束條件才停止遞歸調(diào)用。通過例4-14來了解遞歸調(diào)用的含義。
【例4-14】有5個學(xué)生坐成一排,問第5個學(xué)生的年齡,她說比第4個學(xué)生大2歲;問第4個學(xué)生的年齡,她說比第3個學(xué)生大2歲;問第3個學(xué)生的年齡,她說比第2個學(xué)生大2歲;問第2個學(xué)生的年齡,她說比第1個學(xué)生大2歲;問第1個學(xué)生的年齡,她說她10歲。請問第5個學(xué)生的年齡多大?
根據(jù)題意,第1個學(xué)生是10歲,每個學(xué)生年齡都比其前1個學(xué)生的年齡大2歲。假設(shè)有n個學(xué)生年齡的函數(shù)age($n),第1個學(xué)生是10歲,則可以表示為age(1)=10;要求第5個學(xué)生年齡,就需要知道第4個學(xué)生的年齡,可以表示為age(5)=age(4)+2;要求第4個學(xué)生年齡,就需要知道第3個學(xué)生的年齡,可以表示為age(4)=age(3)+2;要求第3個學(xué)生年齡,就需要知道第2個學(xué)生的年齡,可以表示為age(3)=age(2)+2;要求第2個學(xué)生年齡,就需要知道第1個學(xué)生的年齡,可以表示為age(2)=age(1)+2;當(dāng)看到age(1),就知道age(1)=10。然后再反推即可求出第5個學(xué)生的年齡。
根據(jù)分析,可以寫出如下代碼。

運行結(jié)果:

這個程序中函數(shù)age()被調(diào)用了5次,有age(5)、age(4)、age(3)、age(2)、age(1)。只有age(5)在函數(shù)外調(diào)用一次,其余4次是在age()函數(shù)中調(diào)用,即age()函數(shù)自己調(diào)用自己,遞歸調(diào)用了4次。
- Bootstrap Site Blueprints Volume II
- Docker and Kubernetes for Java Developers
- 摩登創(chuàng)客:與智能手機和平板電腦共舞
- Python for Secret Agents:Volume II
- 劍指Offer(專項突破版):數(shù)據(jù)結(jié)構(gòu)與算法名企面試題精講
- 3D少兒游戲編程(原書第2版)
- Drupal 8 Module Development
- 軟件體系結(jié)構(gòu)
- Photoshop CC移動UI設(shè)計案例教程(全彩慕課版·第2版)
- Learning Unreal Engine Game Development
- Visual Basic程序設(shè)計基礎(chǔ)
- C++服務(wù)器開發(fā)精髓
- SQL Server 2014 Development Essentials
- Effective C++:改善程序與設(shè)計的55個具體做法(第三版)中文版(雙色)
- Analytics for the Internet of Things(IoT)