php閉包相關理解,php什麼時候使用閉包

本文目錄一覽:

PHP中的閉包有什麼用處

閉包其實就是外部函數定義的內部函數。

閉包的作用及好處:閉包給訪問外部函數定義的內部變量創造了條件。也將關於函數的一切封閉到了函數內部,減少了全局變量,這也是閉包的真實含義。

閉包的理解

集合 S 是閉集當且僅當 Cl(S)=S(這裡的cl即closure,閉包)。特別的,空集的閉包是空集,X 的閉包是 X。集合的交集的閉包總是集合的閉包的交集的子集(不一定是真子集)。

閉包是什麼

有限多個集合的並集的閉包和這些集合的閉包的並集相等;零個集合的並集為空集,所以這個命題包含了前面的空集的閉包的特殊情況。無限多個集合的並集的閉包不一定等於這些集合的閉包的並集,但前者一定是後者的父集。

若 A 為包含 S 的 X 的子空間,則 S 在 A 中計算得到的閉包等於 A 和 S 在 X 中計算得到的閉包(Cl_A(S) = A ∩ Cl_X(S))的交集。特別的,S在 A 中是稠密的,當且僅當 A 是 Cl_X(S) 的子集。

閉包包含自由(未綁定到特定對象)變量;這些變量不是在這個代碼塊內或者任何全局上下文中定義的,而是在定義代碼塊的環境中定義(局部變量)。

“閉包” 一詞來源於以下兩者的結合:要執行的代碼塊(由於自由變量被包含在代碼塊中,這些自由變量以及它們引用的對象沒有被釋放)和為自由變量提供綁定的計算環境(作用域)。

閉包

在PHP、Scala、Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby、 Python、Go、Lua、objective c、swift 以及Java(Java8及以上)等語言中都能找到對閉包不同程度的支持。

為什麼需要閉包?閉包是什麼概念?

閉包的英文對應的是Closure,如果要單純的討論這個概念的話就要提到和圖靈機起名的大名鼎鼎的lambda演算(lamdba calculus)。儘管lamdba的概念並不是本文的重點,但是閉包概念的目的便是支持lamdba的實現。如果你單獨地在百度對進行搜索閉包的話,你會發現大部分都是js相關的內容,主要是js本身就只用閉包的這個概念。但是閉包並不僅限於js,而是一個通用的概念。借用wiki中有點抽象的定義來說的話,閉包就是:

在計算機科學中,閉包(英語:Closure),又稱詞法閉包(Lexical Closure)或函數閉包(function closures),是引用了自由變量的函數。

簡單來說就是當一個方法引用了方法局部變量外的變量時,它就是一個閉包。而如果根據這個定義繼續延展的話,就可以得到另外的一種描述方法:

閉包是由函數和與其相關的引用環境(方法外變量)組合而成的實體。

儘管給出了兩種關於閉包是什麼的定義,但是閉包本身的概念還是較為的抽象。比如直接給例子,我們可以先討論一下為什麼需要閉包。

為了理解閉包,我們可以先假設這樣的一種場景:

我有一個方法A,其中有私有變量。我想在別的方法中可以直接訪問並使用它,但是又不想直接暴露它。

這時候,就可以在A建立一個內部類B來訪問私有變量。那麼這時候,這個內部類中你所可以訪問B的方法,就和A中的私有變量形成了閉包。此時B已經捕獲了A中的變量。即便是A對象銷毀了,被B捕獲的私有變量仍然不會釋放。

所以可以理解,如果希望系統 方法和當前環境的上下文綁定 的話,就可以使用閉包。

儘管有些不恰當,但是我們可以再換一個實際的場景來舉個例子幫助你理解:

當你在購物的時候,你選中了一件商品,然後下單。這時候你的訂單就已經綁定了你選中的商品。那麼你的購買行為就和商品組成了閉包。這時候即便商家下架商品,也不會影響到商品後續的發貨簽收。並且這些邏輯只需要根據購買行為中的信息進行判斷就可以了,而不用關心商家什麼時候把商品下架,這寫邏輯發生時候的商品價格是什麼。

結合上面的例子,我們可以發現,當一個方法和其調用的外部環境形成閉包的時候,由於外部環境已經確定,那麼我們就不用再關心外部環境了,而只用關心方法本身。

所以針對我們為什麼需要閉包,我給出的答案是:

使用閉包的設計方式,由於閉包本身已經包含了上下文信息,所以可以對北向功能調用(用戶)屏蔽由於環境而引發的複雜處理和交互成本。

對於Java來說,可以理解為主要是兩種的閉包方式:

其中內部類除了本身的內部類還有局部內部類、匿名內部類。我們以最簡潔的匿名內部類來舉例:

此時say方法中便捕獲了length屬性,而如果你使用的是足夠版本的IDE的話,獲取還會提示你:

Anonymous new ISay() can be replaced with lambda

替換後:

那麼這時候你就會發現,此時return的對象就是一個通過匿名後直接描述的函數,而這個函數同時還關聯了上下文之外的環境信息。

而在java8中lambda的中我們可以通過函數式編程接口直接接收這種閉包,這些接口常用的為:

關於函數式接口本文就不展開了,但是利用函數式接口,我們就可以這樣傳遞一個閉包:

此時say返回的就不是String的結果了,而是直接將閉包本身返回了。而這個閉包在創建的時候就已經綁定了所需要的環境屬性。所以我們可以在需要的時候再調用閉包,並且不用再關心它到底依賴了其他哪些變量:

當然你可能會角色,這個length似乎沒有什麼用呀,那如果我們換一個形式:

使用Spring的依賴注入後,那麼這個Closure類本身可能是各種策略模式策略器中的一個,策略器返回的是一個已經關聯了具體策略路由的閉包。而當這個方法提供出去的時候,後續的調用者只需要知道這個閉包是可以針對文本進行處理的就可以,而至於之前是使用的什麼策略它則不用關心。因為這些細節都已經通過閉包屏蔽了。

僅僅談論好的而對問題閉口不談確實不好,雖然閉包提供了強大的功能,可以對業務細節進行屏蔽,對系統進行接耦拆分。但是閉包本身確實有一些問題需要留意:

可以發現,這兩個問題都是由於閉包本身的優點而產生的。由於閉包關聯了環境信息,所以其讓環境信息中對象的生命周期變長,這對於系統性能的維護以及jvm的垃圾回收都有負面因素。而同時因為不同於一般的編碼風格,閉包的使用需要開發人員對實體進行抽象,才能比較好地實現。總結來說,對於開發人員本身有一定要求。

平時我們也經常使用lambda表達式來處理一些業務邏輯,偶爾會出現一下的情況:

先不管這段代碼的實現業務背景是什麼,但是IDE會提示在userIds.get(i)中的i提示的信息為:

Variable used in lambda expression should be final or effectively final

結合了上文中關於閉包的內容,我們就不難理解。由於閉包是要關聯外部環境變量,在這部分代碼中關聯的是索引變量i,但是因為i本身是局部變量,無法保證關聯環境的穩定性(我自己的理解),所以java編譯器會強制的要求當閉包關聯的是局部變量的時候,需要添加final關鍵字,而在進行final關鍵字從而保證該變量的內存引用不會發生改變。從本章的代碼上結論上看則是進行了一次內存拷貝,來保證每個閉包中關聯的環境變量不會改變,修改後的代碼為:

閉包本身是一種面向抽象編程,屏蔽細節的設計原則。在良好的設計下,可以通過閉包來屏蔽對於環境信息的感知,從而簡化外部對於系統理解的成本,提高系統的易用性。

原創文章,作者:IOVH,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/143504.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
IOVH的頭像IOVH
上一篇 2024-10-22 23:34
下一篇 2024-10-22 23:34

相關推薦

  • PHP和Python哪個好找工作?

    PHP和Python都是非常流行的編程語言,它們被廣泛應用於不同領域的開發中。但是,在考慮擇業方向的時候,很多人都會有一個問題:PHP和Python哪個好找工作?這篇文章將從多個方…

    編程 2025-04-29
  • PHP怎麼接幣

    想要在自己的網站或應用中接受比特幣等加密貨幣的支付,就需要對該加密貨幣擁有一定的了解,並使用對應的API進行開發。本文將從多個方面詳細闡述如何使用PHP接受加密貨幣的支付。 一、環…

    編程 2025-04-29
  • 使用PHP foreach遍歷有相同屬性的值

    本篇文章將介紹如何使用PHP foreach遍歷具有相同屬性的值,並給出相應的代碼示例。 一、基礎概念 在講解如何使用PHP foreach遍歷有相同屬性的值之前,我們需要先了解幾…

    編程 2025-04-28
  • PHP獲取301跳轉後的地址

    本文將為大家介紹如何使用PHP獲取301跳轉後的地址。301重定向是什麼呢?當我們訪問一個網頁A,但是它已經被遷移到了另一個地址B,此時若服務器端做了301重定向,那麼你的瀏覽器在…

    編程 2025-04-27
  • PHP登錄頁面代碼實現

    本文將從多個方面詳細闡述如何使用PHP編寫一個簡單的登錄頁面。 1. PHP登錄頁面基本架構 在PHP登錄頁面中,需要包含HTML表單,用戶在表單中輸入賬號密碼等信息,提交表單後服…

    編程 2025-04-27
  • 蘋果煮粥什麼時候放蘋果

    在煮粥的過程中何時將蘋果加入,這是一個常見的問題。其實,蘋果煮粥是非常健康美味的一道粥品,但要正確的加入蘋果才能達到更好的效果。 一、粥的基本製作方法 煮粥有兩種方法,一種是用粥鍋…

    編程 2025-04-27
  • 國慶長假什麼時候開始實施

    國慶長假是中國的七天長假,通常開始時間在10月1日,結束時間在10月7日。在這個特殊的時期,全國各地人民都將迎來盛大的慶祝活動,但是具體的實施時間卻需要考慮多方面因素。 一、中央政…

    編程 2025-04-27
  • PHP與Python的比較

    本文將會對PHP與Python進行比較和對比分析,包括語法特性、優缺點等方面。幫助讀者更好地理解和使用這兩種語言。 一、語法特性 PHP語法特性: <?php // 簡單的P…

    編程 2025-04-27
  • PHP版本管理工具phpenv詳解

    在PHP項目開發過程中,我們可能需要用到不同版本的PHP環境來試驗不同的功能或避免不同版本的兼容性問題。或者我們需要在同一台服務器上同時運行多個不同版本的PHP語言。但是每次手動安…

    編程 2025-04-24
  • PHP數組去重詳解

    一、array_unique函數 array_unique是php中常用的數組去重函數,它基於值來判斷元素是否重複,具體使用方法如下: $array = array(‘a’, ‘b…

    編程 2025-04-24

發表回復

登錄後才能評論