碎碎念
初學PHP發(fā)現(xiàn)其作用域的概念與Javascript有很大不同,所以記下這些,以免后面搞混了。
變量類別
PHP的變量分為全局變量與局部變量:
局部變量
- 函數(shù)體內(nèi)部聲明的變量
- 局部變量還分為動態(tài)變量與靜態(tài)變量
- 局部變量的作用域僅限于函數(shù)體內(nèi)部,外部是訪問不到的
動態(tài)變量
函數(shù)執(zhí)行完畢后會立即釋放。
靜態(tài)變量
- 可以通過
static關(guān)鍵字聲明 - 其在第一次調(diào)用函數(shù)時相當于初始化靜態(tài)變量,但函數(shù)執(zhí)行完畢后靜態(tài)變量并沒有被釋放,而是被保存在靜態(tài)內(nèi)存中,當再次調(diào)用這個函數(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變量都會被釋放,會得到4個1 => 局部變量中的動態(tài)變量
// 加上了static后,每次調(diào)用后變量并未釋放,而是存進了靜態(tài)變量 => 局部變量中的靜態(tài)變量
全局變量
- 函數(shù)體外部聲明的變量
- 函數(shù)體內(nèi)部通過
global關(guān)鍵字聲明的變量
$m = 3;
$n = 4;
function test() {
var_dump($m, $n); // 此時無法獲取$m,$n
}
// 直接在函數(shù)內(nèi)部訪問全局變量是無法得到的
// 方法1 global關(guān)鍵字
function test1() {
global $m; // 使用全局的變量
global $n;
// global $m, $n;
var_dump($m, $n);
$m = 7; // 此時修改的是全局變量了
$n = 8;
}
test(); // 3 4
var_dump($m, $n); // int 7, int 8
function test1() {
global $i, $j; // 創(chuàng)建全局變量,在全局訪問
$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
只能通過兩種方式,在函數(shù)體內(nèi)部訪問全局變量。
- 通過
global關(guān)鍵字 - 通過
$GLOBALS超全局變量
傳值與傳引用
PHP與Javascript類似,也有值傳遞和引用傳遞的概念,類似js傳入簡單類型的值,不會改變函數(shù)外的值,傳入復雜類型則會改變其自身
默認情況下,函數(shù)參數(shù)都是傳值的。所以在函數(shù)體內(nèi)改變參數(shù)的值也不會影響到函數(shù)外部的值。此外,可以通過再參數(shù)前面加上&符號,代表通過引用內(nèi)存地址傳遞參數(shù),在函數(shù)內(nèi)部對其所作的操作影響。
function test3(&$j) { // 注意&符號
$j+=20;
var_dump($j);
}
$k = 5;
test3($k);
var_dump($k);
// int(25) int(25)
注意這里只有變量才能被當作引用被傳遞,如果按照test3(5)調(diào)用則無效!
可變函數(shù)
// 可變函數(shù) 把函數(shù)名賦給一個變量 變量調(diào)用時會被當作函數(shù)解析
$funcName = 'md5';
echo $funcName("gaohang");
echo "<br>";
echo md5("gaohang");
// 074f69168405a5e892f1d02f12896f3f
// 074f69168405a5e892f1d02f12896f3f
可變函數(shù)不能用于像echo、print、unset()、isset()、empty()、include、require以及類似的結(jié)構(gòu),需要封裝實現(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
所以我們可以定義一個函數(shù),然后將函數(shù)名賦值給變量,用變量來調(diào)用函數(shù)??梢酝ㄟ^get_defined_function()來獲取所有系統(tǒng)變量(internal)和用戶自定義變量(user),一個關(guān)聯(lián)數(shù)組。
回調(diào)函數(shù)
回調(diào)函數(shù)說白了就是把一個函數(shù)當作參數(shù)傳遞進另一個函數(shù),并在函數(shù)內(nèi)調(diào)用!我們可以通過可變函數(shù)的形式進行調(diào)用,或者是call_user_func()與call_user_func_array()進行調(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ù)組進行傳遞的
echo $a."\n";
?>
匿名函數(shù)
也就是閉包,臨時創(chuàng)建一個沒有指定名稱的函數(shù),最經(jīng)常用作回調(diào)函數(shù)參數(shù)的值。此外,匿名函數(shù)也可以作為變量的值來使用。
// 匿名函數(shù) 注意要加分號
$func = function() {
return "this is a function";
};
// 通過可變函數(shù)的形式進行調(diào)用
echo $func();
// 通過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的代碼實現(xiàn)與函數(shù)A完全相同,以此類推,此時就需要封裝成遞歸函數(shù)。
直白的說,就是函數(shù)自己調(diào)用自己,以特殊條件結(jié)束執(zhí)行。
比如PHP實現(xiàn)遍歷目錄,目錄的復制,刪除非空目錄等等操作必須通過遞歸函數(shù)實現(xiàn)。無限極分類(電商網(wǎng)站的分類項目)也必須通過遞歸實現(xiàn)。
// 簡單的遞歸
function test($i) {
echo $i."<br>";
--$i;
if ($i>=0) {
test($i);
}
}
test(5);
5
4
3
2
1
0

使用遞歸時要注意兩個原則:
- 能不用遞歸就不要使用
- 注意遞歸的結(jié)束條件,防止無限遞歸
使用自定義函數(shù)
對于多次使用的自定義函數(shù),我們可以使用require/require_once/inculde/include_once來引用自定義函數(shù),避免多處書寫重復的函數(shù)被。
通過require/require_once包含文件不存在會產(chǎn)生一個致命錯誤和警告,且程序會終止運行。用include則會產(chǎn)生兩個警告,不會終止程序運行。
require與require_once的區(qū)別在于后者只會出現(xiàn)1次包含。
此外,要注意代碼順序,require和include必須出現(xiàn)在調(diào)用之前,注意代碼順序。