PHP 核心特性之匿名函式

2021-09-29 09:27:05 字數 3456 閱讀 1782

提出

在匿名函式出現之前,所有的函式都需要先命名才能使用

function increment($value)

array_map('increment', [1, 2, 3]);

有的時候函式可能只需要使用一次,這時候使用匿名函式會使得**更加簡潔直觀,同時也避免了函式在其他地方被使用

array_map(function($value), [1, 2, 3]);
定義和使用

php 將閉包和匿名函式視為同等概念(本文統稱為匿名函式),本質上都是偽裝成函式的物件。

匿名函式的本質是物件,因此跟物件一樣可將匿名函式賦值給某一變數

$greet = function(string $name)";

}$greet("jack") // hello jack

所有的匿名函式都是 closure 物件的例項

$greet instanceof closure // true
物件並沒有什麼父作用域可言,所以需要使用 use 來手動宣告使用的變數,

$num = 1;

$func = function() use($num)

$func(); // 2

echo $num; // 還是 1

如果要讓匿名函式中的變數生效,需要使用引用傳值

$num = 1;

$func = function() use(&$num)

$func(); // 2

echo $num; // 2

從 php 5.4 開始,在類裡面使用匿名函式時,匿名函式的 $this 將自動繫結到當前類

class foo ;

}}$foo = new foo();

$obj = $foo->bar(); // closure()

$obj(); // foo

如果不想讓自動繫結生效,可使用靜態匿名函式

class foo ;

}}$foo = new foo();

$obj = $foo->bar(); // closure()

$obj(); // using $this when not in object context

匿名函式的本質

匿名函式的本質是 closure 物件,包括了以下五個方法

closure
__construct - 防止匿名函式被例項化

$closure = new \closure();

// php error: instantiation of 'closure' is not allowed

closure::bindto - 複製當前匿名函式物件,繫結指定的 $this 物件和類作用域。通俗的說,就是手動將匿名函式與指定物件繫結,利用這點,可以為擴充套件物件的功能。

// 定義商品類

class good

}// 定義乙個匿名函式,計算商品的**價

$adddiscount = function(float $discount = 0.8)

$good = new good(100);

// 將匿名函式繫結到 $good 例項,同時指定作用域為 good

$count = $adddiscount->bindto($good, good::class);

$count(); // 80

// 將匿名函式繫結到 $good 例項,但是不指定作用域,將無法訪問 $good 的私有屬性

$count = $adddiscount->bindto($good);

$count(); // 報錯

closure::bind - bindto 方法的靜態版本,有兩種用法:

用法一:實現與 bindto 方法同樣的效果

$count = \closure::bind($adddiscount, $good, good::class);
用法二:將匿名函式與類(而不是物件)繫結,記得要將第二個引數設定為 null

// 商品庫存為 10

class good

// 每次銷售後返回當前庫存

$sell = static function() ;

// 將靜態匿名函式繫結到 good 類中

$sold = \closure::bind($sell, null, good::class);

$sold(); // 當前庫存為 9

$sold(); // 當前庫存為 8

call - php 7 新增的 call 方法可以實現繫結並呼叫匿名函式,除了語法更加簡潔外,效能也更高

// call 版本

$adddiscount->call($good, 0.5); // 繫結並傳入引數 0.5,結果為 50

// bindto 版本

$count = $adddiscount->bindto($good, good::class, 0.5);

$count(); // 50

fromcallable - 將給定的 callable 函式轉化成匿名函式

class good 

}function adddiscount(float $discount = 0.8)

$closure = \closure::fromcallable('adddiscount');

$good = new good(100);

$count = $closure->bindto($good);

$count = $closure->bindto($good, good::class); // 報錯,不能重複繫結作用域

$count(); // 報錯,無法訪問私有屬性

fromcallable 等價於

$reflexion = new reflectionfunction('adddiscount');

$closure = $reflexion->getclosure();

這裡有一點需要特別注意的是,無論是 fromcallable 轉化成的閉包,還是使用反射得到的閉包,在使用 bindto 時,如果第二個引數指定繫結類,會報錯

cannot rebind scope of closure created by reflectionfunctionabstract::getclosure()

PHP 核心特性之命名空間

提出 在命名空間提出之前,不同的元件很容易碰到命名的衝突,例如 request response 等常見的命名。php 在 5.3 後提出了命名空間用來解決元件之間的命名衝突問題,主要參考了檔案系統的設計 同乙個目錄下不允許有相同的檔名 同乙個命名空間下不允許有相同的類 不同的目錄可以有同名檔案 不...

Python核心丨匿名函式

描述 匿名函式格式 lambda argument1,argument2,argumentn expression匿名函式的關鍵字是lambda,之後是一系列的引數,然後用冒號隔開,最後則是由這些引數組成的表示式。square lambda x x 2square 3 9寫成常規函式 def squ...

OC高階特性 Block匿名函式

塊是objective c語言提供的乙個強大特性,博主會介紹塊語法的意義 塊記憶體管理 怎樣在程式中開發塊和怎樣使用現有api 如foundation框架 中的塊。簡言之,塊提供了一種方式,使用這種方式可以建立一組語句 即 塊 並將這些語句賦予乙個變數,隨後就可以呼叫這個變數。從這方面看,塊與函式方...