摘要:也就是閑時(shí)為了寫文章而寫的一篇關(guān)于源碼的閱讀筆記。是標(biāo)準(zhǔn)庫的縮寫,一組旨在解決標(biāo)準(zhǔn)問題的接口和類的集合。提供了一套標(biāo)準(zhǔn)的數(shù)據(jù)結(jié)構(gòu),一組遍歷對象的迭代器,一組接口,一組標(biāo)準(zhǔn)的異常,一系列用于處理文件的類,提供了一組函數(shù),具體可以查看文檔。
也就是閑時(shí)為了寫文章而寫的一篇關(guān)于 Pimple 源碼的閱讀筆記。
Pimple 代碼有兩種編碼方式,一種是以 PHP 編寫的,另一種是以 C 擴(kuò)展編寫的方式,當(dāng)然個(gè)人能力有限呀,也就看看第一種了。
Pimple 鏈接前提知識(shí) ArrayAccess(數(shù)組式訪問)接口
官網(wǎng) WebSite
GitHub - Pimple
Pimple 中文版文檔
提供像訪問數(shù)組一樣訪問對象的能力的接口。
http://php.net/manual/zh/clas...
一個(gè) Class 只要實(shí)現(xiàn)以下規(guī)定的 4 個(gè)接口,就可以是像操作數(shù)組一樣操作 Object 了。
ArrayAccess { /* 方法 */ abstract public boolean offsetExists ( mixed $offset ) abstract public mixed offsetGet ( mixed $offset ) abstract public void offsetSet ( mixed $offset , mixed $value ) abstract public void offsetUnset ( mixed $offset ) }
偽代碼如下
class A implements ArrayAccess { // 實(shí)現(xiàn)了 4 個(gè)接口 } $a = new A(); // 可以這么操作 $a["x"] = "x"; // 對應(yīng) offsetSet echo $a["x"]; // 對應(yīng) offsetGet var_dump(isset($a["x"])); // 對應(yīng) offsetExists unset($a["x"]); // 對應(yīng) offsetUnset
特別說明,只支持上面四種操作,千萬別以為實(shí)現(xiàn)了 ArrayAccess,就可以使用 foreach 了,要實(shí)現(xiàn)循環(huán) = 迭代,要實(shí)現(xiàn) Iterator(迭代器)接口,其實(shí) PHP 定義了很多 預(yù)定義接口 有空可以看看。
SPL - SplObjectStorage SPLSPL 是 Standard PHP Library(PHP標(biāo)準(zhǔn)庫)的縮寫,一組旨在解決標(biāo)準(zhǔn)問題的接口和類的集合。SPL 提供了一套標(biāo)準(zhǔn)的數(shù)據(jù)結(jié)構(gòu),一組遍歷對象的迭代器,一組接口,一組標(biāo)準(zhǔn)的異常,一系列用于處理文件的類,提供了一組函數(shù),具體可以查看文檔。
SplObjectStorageSplObjectStorage 是 SPL 標(biāo)準(zhǔn)庫中的數(shù)據(jù)結(jié)構(gòu)對象容器,用來存儲(chǔ)一組對象,特別是當(dāng)你需要唯一標(biāo)識(shí)對象的時(shí)候 。
SplObjectStorage implements Countable , Iterator , Serializable , ArrayAccess { /* * 向 SplObjectStorage 添加一個(gè) object,$data 是可選參數(shù) * 因?yàn)?SplObjectStorage 實(shí)現(xiàn)了 ArrayAccess 的接口,所以可以通過數(shù)組的形式訪問,這里相當(dāng)于設(shè)置 object 為數(shù)組的 key ,data 是對應(yīng)的 value,默認(rèn) data 是 null */ public void attach ( object $object [, mixed $data = NULL ] ) /* * 檢查 SplObjectStorage 是否包含 object ,相當(dāng)于 isset 判斷 */ public bool contains ( object $object ) /* * 從 SplObjectStorage 移除 object ,相當(dāng)于 unset */ public void detach ( object $object ) // 其他接口定義可以自行查看文檔 }
SplObjectStorage 實(shí)現(xiàn)了 Countable、Iterator、Serializable、ArrayAccess 四個(gè)接口,可實(shí)現(xiàn)統(tǒng)計(jì)、迭代、序列化、數(shù)組式訪問等功能,其中 Iterator 和 ArrayAccess 在上面已經(jīng)介紹過了。
魔術(shù)方法 __invoke()__invoke() 當(dāng)嘗試以調(diào)用函數(shù)的方式調(diào)用一個(gè)對象時(shí),__invoke() 方法會(huì)被自動(dòng)調(diào)用。
看一個(gè)例子吧,一目了然。
讀源碼 目錄接口pimple ├── CHANGELOG ├── LICENSE ├── README.rst ├── composer.json ├── ext // C 擴(kuò)展,不展開 │?? └── pimple ├── phpunit.xml.dist └── src └── Pimple ├── Container.php ├── Exception // 異常類定義,不展開 ├── Psr11 │?? ├── Container.php │?? └── ServiceLocator.php ├── ServiceIterator.php ├── ServiceProviderInterface.php └── Tests // 測試文件,不展開PS, Markdown 寫目錄格式真是麻煩,后來找了一個(gè)工具 tree 可以直接生成結(jié)構(gòu)。
Container.phpclass Container implements ArrayAccess { private $values = array(); // 存儲(chǔ) value 的數(shù)組 private $factories; // 存儲(chǔ)工廠方法的對象,是 SplObjectStorage 的實(shí)例 private $protected; // 存儲(chǔ)保護(hù)方法的對象,是 SplObjectStorage 的實(shí)例 // 存儲(chǔ)被凍結(jié)的服務(wù),新設(shè)置一個(gè) service 的時(shí)候,可以在還沒有調(diào)用這個(gè) service 的時(shí)候,覆蓋原先設(shè)置,這時(shí)不算凍結(jié) // 一旦調(diào)用了這個(gè) service 之后,就會(huì)存入 $frozen 數(shù)組,如果這時(shí)還想重新覆蓋這個(gè) service 會(huì)報(bào)錯(cuò),判斷邏輯在 offsetSet 實(shí)現(xiàn)。 private $frozen = array(); private $raw = array(); // 存儲(chǔ) service 原始設(shè)置內(nèi)容,用于 ::raw() 方法讀取 private $keys = array(); // 存儲(chǔ) key public function __construct(array $values = array()) { $this->factories = new SplObjectStorage(); $this->protected = new SplObjectStorage(); foreach ($values as $key => $value) { $this->offsetSet($key, $value); } } public function offsetSet($id, $value){} public function offsetGet($id){} public function offsetExists($id){} public function offsetUnset($id){} public function factory($callable){} public function protect($callable){} public function raw($id){} public function extend($id, $callable){} public function keys(){} public function register(ServiceProviderInterface $provider, array $values = array()){} }Container 實(shí)現(xiàn)了 ArrayAccess 接口,這就可以理解為什么可以通過數(shù)組的方式定義服務(wù)了。
重要的 function 分析1、offsetSet、offsetExists、offsetUnset 主要實(shí)現(xiàn) ArrayAccess 的接口很容易看懂
2、factory、protect 主要邏輯是判斷傳入的 $callable 是否有 __invoke ,如果有的話,通過 SplObjectStorage::attach,存儲(chǔ) object 中
3、raw 獲取設(shè)置的原始內(nèi)容
4、key 獲取所有的 key
5、register() 注冊一些通用的 service6、offsetGet()
public function offsetGet($id) { if (!isset($this->keys[$id])) { // 如果沒有設(shè)置過,報(bào)錯(cuò) throw new UnknownIdentifierException($id); } if ( isset($this->raw[$id]) // raw 里已經(jīng)有值,一般來說就是之前已經(jīng)獲取過一次實(shí)例,再次獲取的時(shí)候,就返回相同的值 || !is_object($this->values[$id]) // 對應(yīng)的 value 不是 object ,而是一個(gè)普通的值 || isset($this->protected[$this->values[$id]]) // 存在于 protected 中 || !method_exists($this->values[$id], "__invoke") // 對應(yīng)的 value 不是閉包 ) { return $this->values[$id]; // 返回 values 數(shù)組里的值 } if (isset($this->factories[$this->values[$id]])) { // 如果工廠方法里面設(shè)置了相關(guān)方法 return $this->values[$id]($this); // 直接調(diào)用這個(gè)方法,傳入?yún)?shù)($this),也就是匿名函數(shù)中可以訪問當(dāng)前實(shí)例的其他服務(wù) } $raw = $this->values[$id]; $val = $this->values[$id] = $raw($this); // 初始化一般的 service ,傳入($this) ,以后再調(diào)用都獲取相同的實(shí)例 $this->raw[$id] = $raw; // 把原始內(nèi)容存入 raw 數(shù)組 $this->frozen[$id] = true; // 在初始化之后凍結(jié)這個(gè) key ,不能被覆蓋 return $val; }7、extend()
擴(kuò)展一個(gè) service,如果已經(jīng)被凍結(jié)了,也不能被擴(kuò)展。
與上文說的直接覆蓋還是有區(qū)別的,直接覆蓋就是完全不管之前定義的 service ,使用 extend 是可以在原始定義上做出修改public function extend($id, $callable) { // ... 一些判斷邏輯省略 // 如果是 protected 的 service 還不被支持 extend if (isset($this->protected[$this->values[$id]])) { @ rigger_error(sprintf("How Pimple behaves when extending protected closures will be fixed in Pimple 4. Are you sure "%s" should be protected?", $id), E_USER_DEPRECATED); } if (!is_object($callable) || !method_exists($callable, "__invoke")) { throw new ExpectedInvokableException("Extension service definition is not a Closure or invokable object."); } $factory = $this->values[$id]; // 主要是這兩行代碼 $extended = function ($c) use ($callable, $factory) { return $callable($factory($c), $c); }; if (isset($this->factories[$factory])) { $this->factories->detach($factory); $this->factories->attach($extended); } return $this[$id] = $extended; }未完待續(xù)。還有一篇,主要關(guān)于 PSR11 兼容性的。
原創(chuàng)文章,歡迎轉(zhuǎn)載。轉(zhuǎn)載請注明出處,謝謝。
原文鏈接地址:http://dryyun.com/2018/04/18/...
作者: dryyun
發(fā)表日期: 2018-04-18 14:36:40
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/28653.html
摘要:服務(wù)容器接口是的簡寫,由組織制定的規(guī)范,是開發(fā)的實(shí)踐標(biāo)準(zhǔn)。實(shí)現(xiàn)的容器類源碼很簡單,主要是傳入變量,然后設(shè)置這個(gè)兩個(gè)方法。原創(chuàng)文章,歡迎轉(zhuǎn)載。原文鏈接地址作者發(fā)表日期 接著上篇 還有一些內(nèi)容沒有寫,上篇已經(jīng)把關(guān)于 Pimple 最主要的代碼分析了一下,這篇主要是關(guān)于 PSR-11 兼容性的分析。 PSR-11 服務(wù)容器接口 PSR PSR 是 PHP Standard Recommend...
摘要:已經(jīng)有了非常好的的相關(guān)解析,建議先看下一個(gè)簡單的依賴注入容器讀源碼筆記上讀源碼筆記下這里通過例子補(bǔ)充下核心方法的說明相關(guān)的類型服務(wù)類似單例工廠服務(wù)多個(gè)實(shí)例參數(shù)僅僅是保存一些變量保護(hù)參數(shù)匿名函數(shù)都會(huì)被認(rèn)為服務(wù),但是如果僅僅是想作為一個(gè) 已經(jīng)有了非常好的Pimple的相關(guān)解析,建議先看下:Pimple - 一個(gè)簡單的 PHP 依賴注入容器讀 PHP - Pimple 源碼筆記(上)讀 PH...
摘要:服務(wù)通過匿名函數(shù)定義,返回一個(gè)對象的實(shí)例定義一些服務(wù)請注意,匿名函數(shù)可以訪問當(dāng)前容器實(shí)例,從而允許引用其他服務(wù)或參數(shù)。如果要為所有調(diào)用返回不同的實(shí)例,請使用方法包裝你的匿名函數(shù)。 鏈接 官網(wǎng) WebSite GitHub - Pimple 這是 Pimple 3.x 的文檔。如果你正在使用 Pimple 1.x ,請查看 Pimple 1.x 文檔。閱讀 Pimple 1.x ...
摘要:實(shí)際上,閉包和匿名函數(shù)是偽裝成函數(shù)的對象。容器流程淺析是社區(qū)中比較流行的容器。服務(wù)提供者服務(wù)提供者是連接容器與具體功能實(shí)現(xiàn)類的橋梁。服務(wù)提供者需要實(shí)現(xiàn)接口所有服務(wù)提供者必須實(shí)現(xiàn)接口方法。但已經(jīng)完成了服務(wù)提供者的注冊工作。 需要具備的知識(shí)點(diǎn) 閉包 閉包和匿名函數(shù)在PHP5.3.0中引入的。 閉包是指:創(chuàng)建時(shí)封裝周圍狀態(tài)的函數(shù)。即使閉包所處的環(huán)境不存在了,閉包中封裝的狀態(tài)依然存在。 理論上...
摘要:安裝代碼加載并實(shí)例化參數(shù)存儲(chǔ)單例存儲(chǔ)非單例存儲(chǔ)存儲(chǔ)匿名函數(shù)獲取匿名函數(shù)服務(wù)提供者文檔官網(wǎng)文檔 Pimple/Container 安裝 composer require pimple/pimple: ^3.0 代碼 加載并實(shí)例化 require __DIR__ . /vendor/autoload.php; $pc = new PimpleContainer(); 參數(shù)存儲(chǔ) $pc[ap...
閱讀 2010·2021-11-24 10:45
閱讀 1867·2021-10-09 09:43
閱讀 1306·2021-09-22 15:38
閱讀 1234·2021-08-18 10:19
閱讀 2852·2019-08-30 15:55
閱讀 3072·2019-08-30 12:45
閱讀 2977·2019-08-30 11:25
閱讀 367·2019-08-29 11:30