小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

【PHP小課堂】PHP中的函數(shù)相關(guān)處理方法學(xué)習(xí)

 硬核項(xiàng)目經(jīng)理 2024-09-16 發(fā)布于湖南

PHP中的函數(shù)相關(guān)處理方法學(xué)習(xí)

在很早之前,面向過程的時(shí)代,函數(shù)方法是這些面向過程語言中的一等公民。在進(jìn)步到面向?qū)ο笾?,函?shù)依然有著舉足輕重的地位,它在類中成為了方法,但本質(zhì)上,方法就是類的內(nèi)部的一個(gè)函數(shù)。一般地,我們會(huì)將類外部定義的 function 稱為函數(shù),而將類的內(nèi)部定義的 function 稱為方法。我們的 PHP 也是從面向過程語言發(fā)展成為面向?qū)ο笳Z言的一門編程語言,所以函數(shù)方法的支持也是非常全面的。今天我們學(xué)習(xí)的內(nèi)容,是和 PHP 的函數(shù)操作有關(guān)的一些函數(shù)方法,它們?yōu)槲覀儾僮骱瘮?shù)方法提供了許多方便有用的功能。

創(chuàng)建匿名函數(shù)

首先是創(chuàng)建一個(gè)匿名函數(shù)的方法,當(dāng)然,之前的許多文章中我們也經(jīng)常使用匿名函數(shù)來演示代碼,不過今天介紹的這個(gè)與之前的匿名函數(shù)創(chuàng)建的方式略有不同。

$func = create_function('$a, $b''return $a+$b;');
echo $func(1,2), PHP_EOL; // 3

create_function() 方法就是用于創(chuàng)建一個(gè)函數(shù),它的第一個(gè)參數(shù)是創(chuàng)建的函數(shù)的參數(shù),第二個(gè)參數(shù)是函數(shù)體內(nèi)部的內(nèi)容。從代碼中可以看出,這種形式創(chuàng)建函數(shù)非常地不直觀,所以現(xiàn)在這個(gè) create_function() 方法已經(jīng)被標(biāo)記為過時(shí)的,并在 PHP8 中不推薦使用了。更好地方式當(dāng)然是直接地寫我們的匿名函數(shù)就可以啦。

$func = function($a, $b){
    return $a+$b;
};
echo $func(12), PHP_EOL; // 3

函數(shù)參數(shù)操作

函數(shù)的參數(shù)操作也是非常常見的應(yīng)用。

// 函數(shù)參數(shù)操作
function test($a, $b){
    var_dump(func_get_args());

    var_dump(func_num_args());

    var_dump(func_get_arg(1));
}

test(1,2,3);
// array(3) {
//     [0]=>
//     int(1)
//     [1]=>
//     int(2)
//     [2]=>
//     int(3)
//   }

// int(3)

// int(3)

func_get_args() 用于獲取全部的參數(shù),func_num_args() 用于獲取參數(shù)的數(shù)量,func_get_arg() 用于獲取指定位置的參數(shù)。PHP 和 Java 等靜態(tài)語言的不同,除了變量類型之外,函數(shù)參數(shù)的不固定性也是其特點(diǎn)之一。這一點(diǎn)即有好處,也有壞處。比如說好處在于我們可以靈活地定義使用方法的參數(shù),就像測(cè)試代碼中的這個(gè) test() 一樣。我們?cè)诙x函數(shù)體的時(shí)候,只寫了兩個(gè)參數(shù),但是我們是可以給它傳遞更多的參數(shù)的。多出來的參數(shù)就必須使用 func_get_arg() 來獲取參數(shù)的值了,不能也沒辦法使用別的方式獲取這個(gè)參數(shù)的內(nèi)容。而壞處就是靈活過頭了就會(huì)缺少契約的限制,從而導(dǎo)致在面向?qū)ο笾械姆椒ǘ鄳B(tài)這一特性在 PHP 中無法簡單的實(shí)現(xiàn),因?yàn)榉椒ǘ鄳B(tài)的一個(gè)重要應(yīng)用就是方法的重載,對(duì)于 Java 等語言來說,改變參數(shù)就可以實(shí)現(xiàn)方法的多種狀態(tài)的重載,而 PHP 中是沒有這種能力的。關(guān)于這方面的內(nèi)容,我們?cè)谥暗奈恼?PHP中的“重載”是個(gè)啥?https://mp.weixin.qq.com/s/oYFp4PEqQu0Wx5Uo-Xnhew 中也講過如何用 PHP 來實(shí)現(xiàn)方法重載多態(tài)的效果,大家可以參考一下。

判斷函數(shù)是否存在

判斷一個(gè)函數(shù)是否已經(jīng)定義,或者說在當(dāng)前的運(yùn)行環(huán)境中是否存在,是很多業(yè)務(wù)和框架開發(fā)中非常常用的功能。

var_dump(function_exists('test')); // bool(true)
var_dump(function_exists('test1')); // bool(false)

var_dump(function_exists('str_replace')); // bool(true)

function_exists() 函數(shù)就是用于這個(gè)判斷的,相信不用過多的解釋了,和 class_exists() 這些都是類似的。不僅能夠判斷我們自定義的函數(shù)方法是否存在,也可以判斷一些系統(tǒng)及擴(kuò)展相關(guān)的函數(shù)是否存在。比如在很多 CMS 開源系統(tǒng)的初始化檢測(cè)中,就一定會(huì)用到這類函數(shù)來檢測(cè)當(dāng)前運(yùn)行環(huán)境是否符合系統(tǒng)的需求。

獲得全部已定義的函數(shù)

通過一個(gè)函數(shù),就可以獲得整個(gè)系統(tǒng)環(huán)境中全部可以使用的方法名稱,感覺怎么樣,是不是很爽?

var_dump(get_defined_functions());
// array(2) {
//     ["internal"]=>
//     array(1544) {
//       [0]=>
//       string(12) "zend_version"
//       [1]=>
//       string(13) "func_num_args"
//       [2]=>
//       string(12) "func_get_arg"
//       [3]=>
//       string(13) "func_get_args"
//       [4]=>
//       string(6) "strlen"
//       [5]=>
//       string(6) "strcmp"
//       …………………………
//       …………………………
//       …………………………
//       …………………………
//       [1540]=>
//       string(15) "xmlwriter_flush"
//       [1541]=>
//       string(2) "dl"
//       [1542]=>
//       string(21) "cli_set_process_title"
//       [1543]=>
//       string(21) "cli_get_process_title"
//     }
//     ["user"]=>
//     array(1) {
//       [0]=>
//       string(4) "test"
//     }
//   }

從輸出的結(jié)果來看,系統(tǒng)或者擴(kuò)展自帶的函數(shù),會(huì)放在 internal 下面,我們當(dāng)前的系統(tǒng)環(huán)境中有 1543 個(gè)函數(shù)。當(dāng)然,這個(gè)數(shù)量是根據(jù)我們不同的 PHP 版本以及安裝的不同的擴(kuò)展會(huì)有差別的。而我們自己定義的函數(shù)則會(huì)在 user 下面展示出來。

匿名回調(diào)方式調(diào)用函數(shù)

接下來就到了我們的重頭戲部分,使用匿名回調(diào)的方式來調(diào)用一個(gè)函數(shù)。先看看怎么用,最后我們?cè)僬f說具體的應(yīng)用場(chǎng)景。

function call($a){
    echo 'This is Test call(), arg is ', $a, PHP_EOL;
}

call_user_func('call''1'); // This is Test call(), arg is 1

沒錯(cuò),如果上面的說明沒看明白的話,看到這個(gè) call_user_func() 函數(shù)或許不少人就明白了。這個(gè)函數(shù)也是很多面試中喜歡出現(xiàn)的一個(gè)函數(shù),因?yàn)樗鋵?shí)是一個(gè)很神奇的函數(shù)。在測(cè)試代碼中,我們可以看到,使用 call_user_func() 方法可以調(diào)用執(zhí)行一個(gè)函數(shù),感覺就和我們正常調(diào)用這個(gè)函數(shù)沒什么區(qū)別呀?別急,我們最后再說這個(gè)問題。

繼續(xù)來看看它的使用。

class A{
    function ACall($a, $b){
        echo 'This is class A Test call(), arg is ', $a, ' and ', $b, PHP_EOL;
    }
}
call_user_func(['A''ACall'], '2''22'); // This is class A Test call(), arg is 2 and 22

call_user_func(function($a)echo 'This is anonymous Test call(), arg is ', $a, PHP_EOL;}, '3'); // This is anonymous Test call(), arg is 3

調(diào)用類中的方法,或者直接使用匿名函數(shù)都是可以的。如果是類中的方法的話,第一個(gè)參數(shù)需要是一個(gè)數(shù)組,這個(gè)數(shù)組中的第一個(gè)元素是類的名稱,第二個(gè)元素是類中的方法名稱。call_user_func() 中第二個(gè)以及后面的參數(shù)是可以有 N 多個(gè)的,它們代表的是傳遞給回調(diào)函數(shù)參數(shù)的參數(shù)值。

當(dāng)然,我們還有更方便的一個(gè)函數(shù)可以傳遞參數(shù)值。

call_user_func_array('call', [1]); // This is Test call(), arg is 1

call_user_func_array(['A''ACall'], [222]); // This is class A Test call(), arg is 2 and 22

或許更多的人會(huì)對(duì)這個(gè) call_user_func_array() 更熟悉。而在面試中,也會(huì)有面試官問 call_user_func() 和 call_user_func_array() 的區(qū)別,這時(shí)就不要犯迷糊了,它們的區(qū)別就是對(duì)于參數(shù)的傳遞方式的不同,call_user_func_array() 的參數(shù)直接是以一個(gè)數(shù)組傳遞給回調(diào)函數(shù)的。

arg = 3;
call_user_func_array(function(&$a)echo 'This is anonymous Test call(), arg is ', $a, PHP_EOL;$a++;}, [&$arg]); // This is anonymous Test call(), arg is 3
echo $arg; // 4

在回調(diào)函數(shù)的操作中,傳遞的參數(shù)值也可以是引用形式的,這一點(diǎn)其實(shí)和普通的函數(shù)調(diào)用是沒有什么區(qū)別的。

調(diào)用靜態(tài)函數(shù)

除了上面調(diào)用普通的函數(shù)以及方法外,PHP 中還提供了調(diào)用靜態(tài)函數(shù)方法當(dāng)做回調(diào)函數(shù)的功能。

class A2 {
    const name = 'A2';
    static function ACall(){
        echo __CLASS__ , ' '__METHOD__' 'static::name , ' ',join(func_get_args(), ','), PHP_EOL;
    }

    static function call(){
        forward_static_call(['A2','ACall'], 12);
        forward_static_call('staticCall'12);
    }
}

function staticCall(){
    echo 'This is staticCall ', join(func_get_args(), ','), PHP_EOL;
}

A2::call();
// A2 A2::ACall A2 1,2
// This is staticCall 1,2

從功能上來看 forward_static_call() 和前面介紹的 call_user_func() 其實(shí)沒什么太大的區(qū)別。而從使用角度看,forward_static_call() 必須是在類的方法中使用的,它可以調(diào)用類外部的函數(shù)。注意,這個(gè) forward_static_call() 方法完全不能在類的外部使用的,直接就會(huì)報(bào)錯(cuò)。

既然說到了靜態(tài)方法,那么靜態(tài)方法的一些特別情況也是我們需要關(guān)注的,比如后期靜態(tài)綁定的一些問題。

class A2Child extends A2{
    const name = 'A2Child';
    static function call(){
        forward_static_call(['A2','ACall'], 12);
        call_user_func(['A2''ACall'], 12);
    }
}
A2Child::call();
// A2 A2::ACall A2Child 1,2
// A2 A2::ACall A2 1,2

幸好 forward_static_call() 對(duì)于后期靜態(tài)綁定的支持是沒有問題的。在上面的測(cè)試代碼中,注意到我們輸出的 static::name ,使用 forward_static_call() 和 call_user_func() 打印出來的結(jié)果是不同的哦。關(guān)于這方面的內(nèi)容,可以參考之前文章 后期靜態(tài)綁定在PHP中的使用https://mp.weixin.qq.com/s/N0rlafUCBFf3kZlRy5btYA 中的講解。

同樣地 forward_static_call() 也有一個(gè) forward_static_call_array() 方法與之相對(duì)應(yīng),也是傳遞參數(shù)的方式不同。

class A3 extends A2{
    const name = 'A3';
    static function call(){
        forward_static_call_array(['A2','ACall'], [12]);
    }
}
A3::call();
// A2 A2::ACall A3 1,2

講完了函數(shù)的使用,接下來我們就好好講一講這些函數(shù)的真實(shí)作用。對(duì)于一個(gè)編程語言來說,過早地初始化暫時(shí)還不需要的內(nèi)容是對(duì)資源的極大浪費(fèi)。而在早期來說,我們?cè)诰幾g啟動(dòng)運(yùn)行一個(gè)應(yīng)用之后,所有的變量、方法、類對(duì)象都會(huì)加載到內(nèi)容中,致使應(yīng)用占用的空間非常龐大。而回調(diào)這種能力的出現(xiàn),大大緩解的這個(gè)問題。為什么這么說呢?回調(diào)就像是事件一樣,觸發(fā)才執(zhí)行,也就是說,我們可以在框架中定義好許多類、函數(shù)、方法,但是只有真正在執(zhí)行到對(duì)應(yīng)的功能時(shí),才實(shí)例化并調(diào)用它們。這個(gè)可以參考 Laravel 中的服務(wù)容器以及路由的實(shí)現(xiàn)。大家可以在 vendor/laravel/framework/src/Illuminate/Routing/Controller.php 看到 callAction() 方法中正是使用了 call_user_func_array() 來實(shí)現(xiàn)路由中控制器的加載的。其實(shí)你在現(xiàn)在比較流行的任意一個(gè)框架的 vendor 目錄中搜索 call_user_func 都可以看到非常多地使用這一系列功能函數(shù)的地方。

綜上所述,call_user_func() 相關(guān)的這幾個(gè)函數(shù),在框架應(yīng)用中非常廣泛,也是我們向更高層次邁進(jìn)所應(yīng)該深入學(xué)習(xí)的內(nèi)容。

在 PHP 中止時(shí)運(yùn)行一個(gè)回調(diào)函數(shù)

最后,我們?cè)賮砜匆粋€(gè)非常簡單的函數(shù),也是我們?cè)谟涗浵到y(tǒng)運(yùn)行信息時(shí)非常常用的一個(gè)函數(shù)。

register_shutdown_function(function(){
    echo join(func_get_args(), ',');
}, 12);
// 1,2

register_shutdown_function() 函數(shù)就是注冊(cè)一個(gè)在 PHP 結(jié)束運(yùn)行時(shí)所執(zhí)行的回調(diào)函數(shù)。不管是整個(gè)腳本執(zhí)行完成還是調(diào)用了 exit 或者 die 結(jié)束運(yùn)行之后,這個(gè)函數(shù)中定義的回調(diào)函數(shù)都會(huì)被執(zhí)行。

總結(jié)

今天學(xué)習(xí)的內(nèi)容最核心的地方就在于 call_user_func() 相關(guān)函數(shù)的應(yīng)用,大家掌握好了嗎?其它的比較有用的包括 function_exists() 和 func_get_arg() 這類的函數(shù)也是非常常見的,也是大家要好好了解掌握的內(nèi)容。另外還有兩個(gè)函數(shù) register_tick_function() 以及 unregister_tick_function() ,這兩個(gè)函數(shù)的使用場(chǎng)景非常少,也不多見,大家可以參考之前的文章 PHP沒有定時(shí)器?https://mp.weixin.qq.com/s/NIYwhVLRl0drIcRvIoWvJA 中的相關(guān)講解說明。

測(cè)試代碼:

https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/04/source/7.PHP%E4%B8%AD%E7%9A%84%E5%87%BD%E6%95%B0%E7%9B%B8%E5%85%B3%E5%A4%84%E7%90%86%E6%96%B9%E6%B3%95%E5%AD%A6%E4%B9%A0.php

參考文檔:

https://www./manual/zh/book.funchand.php

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多