日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > php >内容正文

php

PHP学习笔记(一):理解匿名函数与Closure

發(fā)布時(shí)間:2024/4/14 php 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 PHP学习笔记(一):理解匿名函数与Closure 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1.PHP里的匿名函數(shù)實(shí)質(zhì)是Closure類的實(shí)例

(1)不能自己實(shí)例化Closure類型的對(duì)象,會(huì)觸發(fā)一個(gè)Error

try{$closure = new \Closure(); }catch(Error $e){var_dump($e); }

(2)匿名函數(shù)如何使用父作用域的變量?

答案:使用use()將父作用域的變量加載到匿名函數(shù)對(duì)象的靜態(tài)變量表中

$msg2 = 'Closure!'; $greet = function($msg1)use($msg2){echo $msg1,' ',$msg2,'<br>'; }; $greet('Hello'); echo gettype($greet);//匿名函數(shù)是一個(gè)Object echo get_class($greet);//匿名函數(shù)是類Closure的實(shí)例

注:echo中使用','比'.'效率高,原因是echo執(zhí)行效率比拼接字符串效率高

2.create_function()不是標(biāo)準(zhǔn)的匿名函數(shù)

create_function($params,$operation)創(chuàng)建一個(gè)函數(shù)并返回函數(shù)名稱。

(1)返回的函數(shù)名稱是以‘\0’開頭的全局唯一函數(shù)名稱:

$createFuncName = create_function('$arg1,$arg2','echo $arg1," ",$arg2;');//這里用單引號(hào)定義第一個(gè)參數(shù)是為了防止雙引號(hào)中的變量被解析 echo '創(chuàng)建的函數(shù)名稱看起來(lái)是:',$createFuncName,'<br>';//lambda_1 $createFuncName('Hello','create_function()!'); $myFuncName = trim($createFuncName);//這里不要寫死lambda_1隨著多運(yùn)行幾次函數(shù)返回的名稱會(huì)有變化 try{$myFuncName(); }catch(Error $e){var_dump($e);//Error:Call to undefined function () } echo '實(shí)際上生成的函數(shù)名稱第一個(gè)字符是\0:','<br>'; var_dump($createFuncName);//string(9) "lambda_1" var_dump($myFuncName);//string(8) "lambda_1" //手動(dòng)拼一個(gè)'\0'在前面就ok啦 $myFuncName = chr(0).$myFuncName; $myFuncName('Hello','real function name!'); echo gettype($createFuncName),'<br>';//string 不是匿名函數(shù)

create_function()返回一個(gè)函數(shù)名稱,所以創(chuàng)建的不是標(biāo)準(zhǔn)的匿名函數(shù),而是有系統(tǒng)生成了一個(gè)唯一的函數(shù)名。

3.難啃的骨頭:Closure::bind()和Closure::bindTo()

(1)bind()

借用官方的示例:

class A {private static $sfoo = 1;private $ifoo = 2; } $cl1 = static function() {return A::$sfoo; }; $cl2 = function() {return $this->ifoo; };$bcl1 = Closure::bind($cl1, null, 'A'); $bcl2 = Closure::bind($cl2, new A(), 'A'); echo $bcl1(), "\n";//1 echo $bcl2(), "\n";//2

這里使用一個(gè)php擴(kuò)展zendump來(lái)看一下bind()后發(fā)生了什么變化:

class A {public static $psa = 3;private static $sfoo = 1;private $ifoo = 2; } //增加一個(gè)不進(jìn)行bind()的匿名函數(shù) $closure = function(){$c = A::$psa;zendump_opcodes();return $c; }; $cl1 = static function() {$a = A::$sfoo;zendump_opcodes();//使用擴(kuò)展提供方法打印當(dāng)前匿名函數(shù)執(zhí)行內(nèi)容return $a; }; $cl2 = function() {$b = $this->ifoo;zendump($this);//使用擴(kuò)展提供方法打印當(dāng)前$this變量?jī)?nèi)容 zendump_opcodes();return $b; }; $bcl1 = Closure::bind($cl1, null, 'A'); $bcl2 = Closure::bind($cl2, new A(), 'A');echo $bcl1(), "\n"; echo $bcl2(), "\n"; echo $closure(), "\n"; zendump_class('A');//使用擴(kuò)展提供方法打印類A的基本信息

1)echo $closure();這一步會(huì)打印一個(gè)沒(méi)有被bind()的匿名函數(shù)執(zhí)行情況:

op_array("{closure}") {closure}() refcount(2) addr(0x7f28c4461cb8) vars(1) T(3) filename(/var/www/html/index.php) line(47,51) OPCODE OP1 OP2 RESULT EXTENDED ZEND_FETCH_STATIC_PROP_R "psa" "A" #var0 ZEND_ASSIGN $c #var0 ZEND_INIT_FCALL 80 "zendump_opcodes" 0 ZEND_DO_ICALL ZEND_RETURN $c ZEND_RETURN null 3

這里描述執(zhí)行的函數(shù)是{closure},內(nèi)部獲取了類A的靜態(tài)變量psa;

2)再看echo $bcl1();這一步:

op_array("A::{closure}") {closure}() refcount(3) addr(0x7f28c4462078) vars(1) T(3) filename(/var/www/html/index.php) line(52,56) OPCODE OP1 OP2 RESULT EXTENDED ZEND_FETCH_STATIC_PROP_R "sfoo" "A" #var0 ZEND_ASSIGN $a #var0 ZEND_INIT_FCALL 80 "zendump_opcodes" 0 ZEND_DO_ICALL ZEND_RETURN $a ZEND_RETURN null 1

與1)中對(duì)比,明顯區(qū)別是執(zhí)行的函數(shù)被描述為:A::{closure},所以在這里可以獲取類A的私有靜態(tài)變量sfoo;

3)最后看看echo $bcl2();這一步:

先看$this的輸出情況:

zval(0x7f28c44132f0) -> object(A) addr(0x7f28c4457310) refcount(2) {default_properties(1) {$ifoo =>zval(0x7f28c4457338) : long(2)}static_members(2) {$psa =>zval(0x7f28c4470900) : long(3)$sfoo =>zval(0x7f28c4470910) : long(1)} }

這里描述匿名函數(shù)$bcl2中使用的$this是類A的對(duì)象,再看看匿名函數(shù)$bcl2的情況:

op_array("A::{closure}") {closure}() refcount(3) addr(0x7f28c44621b8) vars(1) T(5) filename(/var/www/html/index.php) line(57,62) OPCODE OP1 OP2 RESULT EXTENDED ZEND_FETCH_OBJ_R "ifoo" #var0 ZEND_ASSIGN $b #var0 ZEND_INIT_FCALL 96 "zendump" 1 ZEND_FETCH_THIS #var2 ZEND_SEND_VAR #var2 1 ZEND_DO_ICALL ZEND_INIT_FCALL 80 "zendump_opcodes" 0 ZEND_DO_ICALL ZEND_RETURN $b ZEND_RETURN null 2

這里描述匿名方法$bcl2為A::{closure},所以這里可以通過(guò)指向類A對(duì)象實(shí)例的$this獲取類A的私有變量ifoo。

2)bindTo()

使用同上的方法查看官方示例代碼的zendump情況:

class B {function __construct($val) {$this->val = $val;}function getClosure() {return function() {$val = $this->val;zendump($this);zendump_opcodes();return $val; };} } $ob1 = new B(1); $ob2 = new B(2);$cl = $ob1->getClosure(); echo $cl(), "\n"; $cl = $cl->bindTo($ob2); echo $cl(), "\n";

1)先看第一次執(zhí)行匿名函數(shù)的情況:

zval(0x7f28c4413290) -> object(B) addr(0x7f28c4456758) refcount(3) {properties(1) {"val" =>zval(0x7f28c4461ca0) : long(1)} } op_array("B::{closure}") {closure}() refcount(2) addr(0x7f28c4461f38) vars(1) T(5) filename(/var/www/html/index.php) line(76,81) OPCODE OP1 OP2 RESULT EXTENDED ZEND_FETCH_OBJ_R "val" #var0 ZEND_ASSIGN $val #var0 ZEND_INIT_FCALL 96 "zendump" 1 ZEND_FETCH_THIS #var2 ZEND_SEND_VAR #var2 1 ZEND_DO_ICALL ZEND_INIT_FCALL 80 "zendump_opcodes" 0 ZEND_DO_ICALL ZEND_RETURN $val ZEND_RETURN null 1

這里匿名函數(shù)$cl內(nèi)部的$this是B(1)實(shí)例,匿名函數(shù)被描述為B::{closure};

2)再看看bindTo()另一個(gè)類B實(shí)例后的變化:

zval(0x7f28c4413290) -> object(B) addr(0x7f28c44566e0) refcount(3) {properties(1) {"val" =>zval(0x7f28c4461de0) : long(2)} } op_array("B::{closure}") {closure}() refcount(2) addr(0x7f28c4462078) vars(1) T(5) filename(/var/www/html/index.php) line(76,81) OPCODE OP1 OP2 RESULT EXTENDED ZEND_FETCH_OBJ_R "val" #var0 ZEND_ASSIGN $val #var0 ZEND_INIT_FCALL 96 "zendump" 1 ZEND_FETCH_THIS #var2 ZEND_SEND_VAR #var2 1 ZEND_DO_ICALL ZEND_INIT_FCALL 80 "zendump_opcodes" 0 ZEND_DO_ICALL ZEND_RETURN $val ZEND_RETURN null 2

這里$this的內(nèi)容發(fā)生了變化,變成了B(2)實(shí)例,匿名函數(shù)仍然被描述為B::{closure}。

原理還是沒(méi)有理清楚,不過(guò)可以通過(guò)A::{closure}這種描述以及$this的實(shí)例內(nèi)容的變化,在一定程度上幫助理解bind()和bindTo()的表現(xiàn)。

轉(zhuǎn)載于:https://www.cnblogs.com/ling-diary/p/9121398.html

總結(jié)

以上是生活随笔為你收集整理的PHP学习笔记(一):理解匿名函数与Closure的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。