碎碎念
初學(xué)PHP發(fā)現(xiàn)其作用域的概念與Javascript有很大不同诡壁,所以記下這些顷级,以免后面搞混了麦萤。
變量類別
PHP的變量分為全局變量與局部變量:
局部變量
- 函數(shù)體內(nèi)部聲明的變量
- 局部變量還分為動(dòng)態(tài)變量與靜態(tài)變量
- 局部變量的作用域僅限于函數(shù)體內(nèi)部缕陕,外部是訪問(wèn)不到的
動(dòng)態(tài)變量
函數(shù)執(zhí)行完畢后會(huì)立即釋放味滞。
靜態(tài)變量
- 可以通過(guò)
static
關(guān)鍵字聲明 - 其在第一次調(diào)用函數(shù)時(shí)相當(dāng)于初始化靜態(tài)變量全封,但函數(shù)執(zhí)行完畢后靜態(tài)變量并沒(méi)有被釋放,而是被保存在靜態(tài)內(nèi)存中桃犬,當(dāng)再次調(diào)用這個(gè)函數(shù)時(shí)刹悴,首先從靜態(tài)內(nèi)存中取出變量的值繼續(xù)執(zhí)行。
function test() {
static $j = 1;
echo $j."<br>";
++$j;
}
test(); // 初次調(diào)用 1
test(); // 2
test(); // 3
test(); // 4
// 如果$j不是static聲明攒暇,則每次調(diào)用后$j變量都會(huì)被釋放土匀,會(huì)得到4個(gè)1 => 局部變量中的動(dòng)態(tài)變量
// 加上了static后,每次調(diào)用后變量并未釋放形用,而是存進(jìn)了靜態(tài)變量 => 局部變量中的靜態(tài)變量
全局變量
- 函數(shù)體外部聲明的變量
- 函數(shù)體內(nèi)部通過(guò)
global
關(guān)鍵字聲明的變量
$m = 3;
$n = 4;
function test() {
var_dump($m, $n); // 此時(shí)無(wú)法獲取$m,$n
}
// 直接在函數(shù)內(nèi)部訪問(wèn)全局變量是無(wú)法得到的
// 方法1 global關(guān)鍵字
function test1() {
global $m; // 使用全局的變量
global $n;
// global $m, $n;
var_dump($m, $n);
$m = 7; // 此時(shí)修改的是全局變量了
$n = 8;
}
test(); // 3 4
var_dump($m, $n); // int 7, int 8
function test1() {
global $i, $j; // 創(chuàng)建全局變量就轧,在全局訪問(wèn)
$i = 9;
$j = 10;
}
test1();
var_dump($m, $n);
// 方法2 $GLOBALS超全局變量
$username="gaohang";
$age=12;
$mail="isaackao@foxmail.com";
print_r($GLOBALS);
function test2() {
echo "用戶名是".$GLOBALS['username']."<br>";
echo "年齡是".$GLOBALS['age']."<br>";
echo "郵箱是".$GLOBALS['mail']."<br>";
}
test2();
// 用戶名是gaohang 年齡是12 郵箱是isaackao@foxmail.com
只能通過(guò)兩種方式,在函數(shù)體內(nèi)部訪問(wèn)全局變量田度。
- 通過(guò)
global
關(guān)鍵字 - 通過(guò)
$GLOBALS
超全局變量
傳值與傳引用
PHP與Javascript類似妒御,也有值傳遞和引用傳遞的概念,類似js傳入簡(jiǎn)單類型的值镇饺,不會(huì)改變函數(shù)外的值乎莉,傳入復(fù)雜類型則會(huì)改變其自身
默認(rèn)情況下,函數(shù)參數(shù)都是傳值的奸笤。所以在函數(shù)體內(nèi)改變參數(shù)的值也不會(huì)影響到函數(shù)外部的值惋啃。此外,可以通過(guò)再參數(shù)前面加上&符號(hào)监右,代表通過(guò)引用內(nèi)存地址傳遞參數(shù)边灭,在函數(shù)內(nèi)部對(duì)其所作的操作影響。
function test3(&$j) { // 注意&符號(hào)
$j+=20;
var_dump($j);
}
$k = 5;
test3($k);
var_dump($k);
// int(25) int(25)
注意這里只有變量才能被當(dāng)作引用被傳遞健盒,如果按照test3(5)
調(diào)用則無(wú)效绒瘦!
可變函數(shù)
// 可變函數(shù) 把函數(shù)名賦給一個(gè)變量 變量調(diào)用時(shí)會(huì)被當(dāng)作函數(shù)解析
$funcName = 'md5';
echo $funcName("gaohang");
echo "<br>";
echo md5("gaohang");
// 074f69168405a5e892f1d02f12896f3f
// 074f69168405a5e892f1d02f12896f3f
可變函數(shù)不能用于像echo、print扣癣、unset()惰帽、isset()、empty()搏色、include善茎、require以及類似的結(jié)構(gòu),需要封裝實(shí)現(xiàn)频轿。
自定義函數(shù)
function custom() {
echo "this is a test function!";
}
$customFunc = 'custom';
var_dump($customFunc); // string(6) "custom"
$customFunc(); // this is a test function!
$customFunc = 'hahahah';
var_dump($customFunc); // "hahahah"
$customFunc(); // Fatal error: Uncaught Error: Call to undefined function hahahah() in xxxx
所以我們可以定義一個(gè)函數(shù)垂涯,然后將函數(shù)名賦值給變量烁焙,用變量來(lái)調(diào)用函數(shù)「福可以通過(guò)get_defined_function()
來(lái)獲取所有系統(tǒng)變量(internal)和用戶自定義變量(user)骄蝇,一個(gè)關(guān)聯(lián)數(shù)組。
回調(diào)函數(shù)
回調(diào)函數(shù)說(shuō)白了就是把一個(gè)函數(shù)當(dāng)作參數(shù)傳遞進(jìn)另一個(gè)函數(shù)操骡,并在函數(shù)內(nèi)調(diào)用九火!我們可以通過(guò)可變函數(shù)的形式進(jìn)行調(diào)用,或者是call_user_func()
與call_user_func_array()
進(jìn)行調(diào)用册招;
- call_user_func():Calls the callback given by the first parameter and passes the remaining parameters as arguments.
<php?
function increment(&$var)
{
$var++;
}
$a = 0;
call_user_func('increment', $a);
echo $a."\n";
// You can use this instead
call_user_func_array('increment', array(&$a)); // 注意這里參數(shù)是使用數(shù)組進(jìn)行傳遞的
echo $a."\n";
?>
匿名函數(shù)
也就是閉包岔激,臨時(shí)創(chuàng)建一個(gè)沒(méi)有指定名稱的函數(shù),最經(jīng)常用作回調(diào)函數(shù)參數(shù)的值是掰。此外虑鼎,匿名函數(shù)也可以作為變量的值來(lái)使用。
// 匿名函數(shù) 注意要加分號(hào)
$func = function() {
return "this is a function";
};
// 通過(guò)可變函數(shù)的形式進(jìn)行調(diào)用
echo $func();
// 通過(guò)create_function創(chuàng)建匿名函數(shù)
create_function(參數(shù)列表,函數(shù)體)
$func = create_function('','"this is a function";');
$func();
// 匿名函數(shù)作為參數(shù)傳入
$array=array(1,2,3,4,5);
$res=array_map(function($var) {return $var*2;}, $array);
call_user_func(function($var) {echo "Hello {$var}";}, 'gaohang');
遞歸函數(shù)
如果函數(shù)A需要調(diào)用函數(shù)B键痛,而發(fā)現(xiàn)函數(shù)B的代碼實(shí)現(xiàn)與函數(shù)A完全相同炫彩,以此類推,此時(shí)就需要封裝成遞歸函數(shù)絮短。
直白的說(shuō)江兢,就是函數(shù)自己調(diào)用自己,以特殊條件結(jié)束執(zhí)行丁频。
比如PHP實(shí)現(xiàn)遍歷目錄杉允,目錄的復(fù)制,刪除非空目錄等等操作必須通過(guò)遞歸函數(shù)實(shí)現(xiàn)限府。無(wú)限極分類(電商網(wǎng)站的分類項(xiàng)目)也必須通過(guò)遞歸實(shí)現(xiàn)夺颤。
// 簡(jiǎn)單的遞歸
function test($i) {
echo $i."<br>";
--$i;
if ($i>=0) {
test($i);
}
}
test(5);
5
4
3
2
1
0
使用遞歸時(shí)要注意兩個(gè)原則:
- 能不用遞歸就不要使用
- 注意遞歸的結(jié)束條件,防止無(wú)限遞歸
使用自定義函數(shù)
對(duì)于多次使用的自定義函數(shù)胁勺,我們可以使用require/require_once/inculde/include_once來(lái)引用自定義函數(shù),避免多處書寫重復(fù)的函數(shù)被独旷。
通過(guò)require/require_once包含文件不存在會(huì)產(chǎn)生一個(gè)致命錯(cuò)誤和警告署穗,且程序會(huì)終止運(yùn)行。用include則會(huì)產(chǎn)生兩個(gè)警告嵌洼,不會(huì)終止程序運(yùn)行案疲。
require與require_once的區(qū)別在于后者只會(huì)出現(xiàn)1次包含。
此外麻养,要注意代碼順序褐啡,require和include必須出現(xiàn)在調(diào)用之前,注意代碼順序鳖昌。