本節講解的內容
- 函數的概念
- 函數的分類
- 函數的變量問題
- 函數的參數討論
- 內部函數
- 可變函數
- 匿名函數
- 函數的遞歸調用
前言
在PHP開發中,我們有時候會使用到大量的函數,那什麼是函數,作用又是什麼?函數的出現可以說初次引出了封裝的概念,函數的使用可以使我們的代碼不那麼冗餘,同時函數的定義可以上我們快速的濾清思路。提高代碼的複用性,同時有利於模塊化編程。
函數的概念
當我們在編程中,有這樣一個需求,需要對一個功能進行統一的整合,以便於在別的地方使用這個功能的時候不用在編寫一次(減少冗餘性),只需要調用特定的代碼就能實現。用現成的技術,我們很難實現這種需求,這時就需要使用到函數這個知識。
函數:爲完成某一功能的程序指令(語句)的集合,一般一個函數最好只完成一個功能,降低代碼的耦合度。
有時候我們把函數稱之爲方法,它們兩個是一個概念。
函數的分類
幾乎每種編程語言的函數都分爲兩種:
- 自定義函數
- 系統函數
自定義函數:
自定義函數就是我們自己根據自己的具體需求自己定義的函數,函數中的功能需要自己去實現。
自定義函數的語法規則:
function 方法名(形參列表){
實現某種功能的代碼;
return 返回值(可以沒有返回值,這個看需求)
}
解釋:
- function是一個關鍵字,如果想定義一個函數必須寫function
- 方法名是自己定義的,這個名字你可以隨意起,但是一般我們應該起有意義的名字,比如說這個函數要實現什麼功能的縮寫。
- 形參列表,當我們調用函數的時候,有時候需要傳遞給函數一些參數(也就是變量),在函數中進行操作,這個形參列表就是接受我們調用時傳過來的參數,當然可以有多個。
- 在PHP中函數體是需要大括號包裹起來的,裏面寫我們的代碼。
- return就是返回的意思,當我們調用函數後,有時候需要函數向我們返回一個結果,比如函數的功能是計算兩個數的和,這時候當函數通過進行加法運算後,我們可以寫return返回計算後的結果,當然有沒有返回值需要看函數的具體功能是什麼,需不需要返回結果。
函數名的命名規則:
函數名和 PHP 中的其它標識符命名規則相同。有效的函數名以字母或下劃線打頭,後面跟字母,數字或下劃線。
我們在寫函數是一般的命名規範是駝峯式命名法,也就是第二個單詞的首字母大寫。
示例:
<?php
$a = 12;
$b = 6;
function sum($num1,$num2){//這兩個參數就是接受我們調用時傳過來的參數
$res = $num1 + $num2;
return $res; //計算完兩個數的和,返回給調用者。
}
$sum = sum($a,$b); //調用函數,在這裏我們會傳過去兩個參數,同時返回結果用$sum接收。
echo $sum;
系統函數:
系統函數就是也是函數的一種,是系統已經封裝好的函數,系統函數有好多,不同的函數有不同的功能,我們可以根據自己的需求選取不同的函數。
在幫助文檔中我們可以查詢到我們經常使用的數學函數:
- abs — 絕對值
- ceil — 進一法取整
- decbin — 十進制轉換爲二進制
- dechex — 十進制轉換爲十六進制
- decoct — 十進制轉換爲八進制
- max — 找出最大值
- min — 找出最小值
- pow — 指數表達式
- rand — 產生一個隨機整數
- round — 對浮點數進行四捨五入
- sqrt — 平方根
向我們有時使用的var_dump()輸出類型就是系統函數。
系統函數使用到的時候可以查看幫助文檔。
函數的變量問題
全局變量和局部變量
局部變量:
在函數中我們在處理數據中,可能會定義一些變量,這些在函數中定義的變量我們稱之爲局部變量,局部:顧名思義,就是在函數中使用的變量。
<?php
$a = 12;
$b = 6;
function sum($num1,$num2){
$res = $num1 + $num2; //定義了一個變量用來存儲兩個數的和。
return $res;
}
$sum = sum($a,$b);
echo $res; //嘗試在函數外進行輸出。
echo $sum;
.....結果.....
Notice: Undefined variable: res in D:\mywamp\Apache24\htdocs\zendstudio\yunsuanfu\yusuanfu.php on line 14
18
可以看到當嘗試在函數外使用函數內的變量的時候,就會報錯。
全局變量:
在上面的代碼中我們可以看到在函數外,我們定義兩個變量,
<?php
$a = 12;
$b = 6;
function sum($num1,$num2){
$res = $num1 + $num2;
echo $a;//在函數內輸出函數外的變量。
return $res;
}
$sum = sum($a,$b);
echo $sum;
.....結果.....
Notice: Undefined variable: a in D:\mywamp\Apache24\htdocs\zendstudio\yunsuanfu\yusuanfu.php on line 10
可以看到,在函數內使用函數外的全局變量時,提示錯誤。
全局變量稱爲全局,那怎麼在函數內使用呢?答案很簡單,只需要在函數中用關鍵字聲明一下就行了。
<?php
$a = 12;
$b = 6;
function sum($num1,$num2){
$res = $num1 + $num2;
global $a;//在函數內輸出函數外的變量。
echo $a;
return $res;
}
$sum = sum($a,$b);
.....結果.....
12
在函數中利用global這個關鍵字進行聲明,便是需要使用全局變量$a,在這裏不得不說一下函數的調用在內存中的變化。
函數的調用過程大致圖:
我們的代碼都是在棧(也就是內存中)中運行的。在棧中通過一行行的執行代碼,進行解析,在運行的時候有一個存放我們數據的區域,叫數據區。當定義變量的時候,在數據區就會生成一個數據區,存放自己定義的變量。
當代碼執行到調用函數的時候,系統就會在棧中重新開闢一個棧區,並在這個新棧中執行函數(每執行一個函數就會開闢一個新棧),當在函數中創建對象的時候,就會在數據區重新定義一個區域用來存放函數中的變量。這就是在函數外不能使用函數內變量的原因。它們兩個是兩個不同的區域。
但是當我們聲明瞭global的時候,系統就不會在函數自己的數據區建立一個變量,而是會去函數外部的數據區,嘗試尋找用global定義的變量。但是當外部的數據區沒有我們用global定義的變量的時候,就會自動的在外部的數據區定義一個變量,使其成爲全局變量。
<?php
$b = 6;
function sum($num1){
global $a;//在函數內通過global定義一個外部沒有的變量。
$a = 23; //在函數內進行賦值。
}
$sum = sum($b);
echo $a; //直接使用函數內的變量。
.....結果.....
23
上面的$a在外部沒有定義
函數的參數討論
我們在調用函數的時候經常會去傳過去參數,而在函數上我們也定義了參數進行接受。調用函數時傳的參數稱爲實際參數(實參),而函數接受的參數稱爲形式參數(形參),它兩個是沒有影響的,定義時名字一樣也是可以的,但是一定要對應,不能出現調用時傳過去兩個參數,接收時一個參數。
函數的參數是允許有默認值的,也就是當我們沒有傳過去數值時,它使用默認值,但是當我們傳過去有值的時候,使用我們傳過去的值。
使用默認的:
<?php
$a = 3;
$b = 6;
function sum($a,$b,$oper = '+'){ //形參和實參名字可以使一樣的。
if($oper == '+'){
echo $a + $b; //使用默認的加
}else if($oper == '-'){
echo $a - $b;
}
}
$sum = sum($a,$b); //只傳進去兩個參數,運算符使用默認的情況。
.....結果.....
9
可以看到它並沒有報錯,同時$oper使用了默認的值+;
使用傳過去的:
<?php
$a = 3;
$b = 6;
function sum($a,$b,$oper = '+'){ //形參和實參名字可以使一樣的。
if($oper == '+'){
echo $a + $b;
}else if($oper == '-'){
echo $a - $b;//使用傳過來的加
}
}
$sum = sum($a,$b,'-'); //傳過去三個參數。
參數的值傳遞和引用傳遞
在函數的調用中,參數的傳遞有兩種方式:
- 值傳遞
- 引用傳遞
值傳遞
當我們在調用函數,傳遞參數後在函數中進行修改,而在函數外再次使用,還是修改前的值,可以看代碼:
<?php
$a = 12;
function setA($a){
$a = $a * 12; //把$a的值乘以12;
}
setA($a);//調用函數
echo $a;
.....結果.....
12
這種傳遞方式我們爲值傳遞,默認情況下,函數參數通過值傳遞(因而即使在函數內部改變參數的值,它並不會改變函數外部的值)。如果希望允許函數修改它的參數值,必須通過引用傳遞參數。
引用參數
有時我們希望我們傳進去的值,在沒有返回的情況下,直接進行修改,這是就需要用到引用傳遞。
<?php
$a = 12;
function setA(&$a){ //只是在前面加了一個取地址符號。
$a = $a * 12; //把$a的值乘以12;
//函數沒有返回值
}
setA($a);//調用函數
echo $a;
.....結果.....
144
在上面的代碼中只是在函數中添加了一個取地址符&,學過C語言的都知道,在C語言中使用&直接進行地址的傳遞。這就表示它在函數中的數據,會指向外邊的變量。
內部函數
內部函數: 函數內部可以申明函數,供函數內部使用,稱爲內部函數
,比如某位程序員爲防止他人調用,可以使用內部函數。
<?php
$a = 12;
$b = 6;
function calculator($a,$b){
function sum($a,$b){ //在函數內部定義一個函數,
return $a + $b;
}
function subtract($a,$b){
return $a - $b;
}
return sum($a,$b); // 調用自己定義的函數,把傳進來的兩個值直接傳過去。
}
echo calculator($a,$b); //調用函數,對返回結果直接進行輸出。
.....結果.....
18
其實內部函數也是可以在函數外邊使用的,就像上面的代碼, 如果我們沒有執行 calcuator, 就去調用內部函數 sum() ,就會報錯。但是如果我們執行過 calculator 則,我們也可以使用內部函數了.
<?php
$a = 12;
$b = 6;
function calculator($a,$b){
function sum($a,$b){ //在函數內部定義一個函數,
return $a + $b;
}
function subtract($a,$b){
return $a - $b;
}
}
calculator($a,$b); //調用函數
echo sum($a,$b); //當上面的調用過之後才能這樣調用,不然會出錯。
.....結果.....
18
當調用過calcuator,可以理解爲內存中有函數內的這兩個函數,然後接着調用函數內的函數,就不會出錯。
可變函數
可變函數: PHP 支持可變函數的概念。這意味着如果一個變量名後有圓括號,PHP 將尋找與變量的值同名的函數,並且嘗試執行它。可變函數可以用來實現包括回調函數,函數表在內的一些用途。
看代碼可以比較清晰的理解什麼是可變函數。
<?php
$a = 12;
$b = 6;
function add($a,$b){
$res = $a + $b;
echo $res;
}
$fun_name = 'add';//定義一個變量,這個變量的名字是函數的函數名。
$fun_name($a,$b); //把變量當成一個函數名
.....結果.....
18
我們在回調函數中會使用到這種方式。
案列:
<?php
$a = 6;
$b = 6;
function getVal($a,$b,$fun_name){ //第三個參數是一個函數的名字。
return $fun_name($a,$b); //如果一個變量名後有圓括號,尋找與變量的值同名的函數,並且嘗試執行它。
}
function sum($a,$b){ //在getVal中實際上調用的就是這個函數。
return $a + $b;
}
echo getVal($a,$b,'sum');
.....結果.....
12
在上面把一個函數的名字當成變量進行傳遞。
匿名函數
匿名函數: 匿名函數,也叫閉包函數,允許臨時創建一個沒有指定名稱的函數。最經常用作回調函數參數的值。當然,也有其它應用的情況. 簡單的理解就是 匿名函數就是沒有名字的函數。
<?php
$a = 6;
$b = 16;
function getVal($a,$b,$fun_name){
return $fun_name($a,$b);
}
echo getVal($a,$b,function($a,$b){ //在傳遞的時候臨時的定義一個匿名函數,沒有名字,只有關鍵字function。
return $a + $b;
});
.....結果.....
22
回調函數
上面的代碼其實也是一個回調函數。匿名函數當作回調函數來調用。
回調函數簡單的理解是:你調用了某個函數,而這個函數(A)內又會調用一個由你實現的另一個函數(B),那麼這個另一個函數(B)就是所謂的回調函數,所以,一般來說,你只是不直接去調用罷了。
函數的遞歸調用
遞歸直白的說就是自己調用自己,比如函數自己調用自己,遞歸是一種算法,它的專業說法是:
遞歸通過把一個大型複雜的問題層層轉化爲一個與原問題相似的規模較小的問題來求解,遞歸策略只需少量的程序就可描述出解題過程所需要的多次重複計算,大大的減少了程序的代碼量。
我們在這裏只是簡單的討論一下,不做過多的深入。
示例:
<?php
function abc($n){
if($n > 2){
abc(--$n); //進行自己調用自己。
}
echo '$n的值是' . $n . '<br>';
}
abc(4);
.....結果.....
2 2 3
看到結果可能一時沒有反應過來。但是如果畫圖就好理解了。
函數的遞歸需要滿足幾個條件:
- 基準情形。必須總要有某些基準條件,它無需遞歸就能解出
- 不斷推進。對於那些需要遞歸的求解的情形,每一次遞歸調用都必須要使狀況朝向一種基準情形推進
總結
上面的講解的基本上是函數的基本應用,想要熟悉的掌握函數的應用,只用多練,多想。同時,不知道有沒有發現,本節的函數都是寫在一個文件裏面的,但是有時我們寫的函數是在另外一個文件,這時就不能再另外一個文件直接使用,上面的所有功能都不能使用,作爲PHP程序員,你必須要知道,必然有一種方法能解決這種問題,恩,確實能解決,include和require。