PHP預約義接口之 ArrayAccess

  最近這段時間回家過年了,博客也沒有更新,感受少學習了好多東西,也錯失了好多的學習機會,就像你們在春節搶紅包時常說的一句話:一不留神錯過了好幾億。廢話少說,這篇博客給你們說說關於PHP預約義接口中經常使用到的重量級人物: ArrayAccess。你們也許會問,最基本、最經常使用的預約義接口有6個呢,爲啥非得說這個。從平常的使用狀況來看:這個出現的頻率很是高,特別是在框架中,好比Laravel、Slim等都會用到,而且用得很是經典,讓人佩服啊。從技術上說:說實話其餘的我用的少啊!只是知道簡單的用法,對他的理解比較淺顯,不敢在這裏誤導你們,哈哈!今天我要寫的內容也不必定都正確,不對之處還請指正。php

ArrayAccess html

  先說 ArrayAccess 吧!ArrayAccess 的做用是使得你的對象能夠像數組同樣能夠被訪問。應該說 ArrayAccess 在PHP5中才開始有的,PHP5中加入了不少新的特性,固然也使類的重載也增強了,PHP5 中添加了一系列接口,這些接口和實現的 Class 統稱爲 SPL。數組

ArrayAccess 這個接口定義了4個必需要實現的方法:閉包

1 {
2    abstract public offsetExists ($offset)  //檢查偏移位置是否存在
3    abstract public offsetGet ($offset)     //獲取一個偏移位置的值
4    abstract public void offsetSet ($offset ,$value) //設置一個偏移位置的值
5    abstract public void offsetUnset ($offset)       //復位一個偏移位置的值
6 }

因此咱們要使用ArrayAccess這個接口,就要實現相應的方法,這幾個方法不是隨便寫的,咱們能夠看一下 ArrayAccess 的原型:app

 1 /**
 2  * Interface to provide accessing objects as arrays.
 3  * @link http://php.net/manual/en/class.arrayaccess.php
 4  */
 5 interface ArrayAccess {
 6 
 7     /**
 8      * (PHP 5 &gt;= 5.0.0)<br/>
 9      * Whether a offset exists
10      * @link http://php.net/manual/en/arrayaccess.offsetexists.php
11      * @param mixed $offset <p>
12      * An offset to check for.
13      * </p>
14      * @return boolean true on success or false on failure.
15      * </p>
16      * <p>
17      * The return value will be casted to boolean if non-boolean was returned.
18      */
19     public function offsetExists($offset);
20 
21     /**
22      * (PHP 5 &gt;= 5.0.0)<br/>
23      * Offset to retrieve
24      * @link http://php.net/manual/en/arrayaccess.offsetget.php
25      * @param mixed $offset <p>
26      * The offset to retrieve.
27      * </p>
28      * @return mixed Can return all value types.
29      */
30     public function offsetGet($offset);
31 
32     /**
33      * (PHP 5 &gt;= 5.0.0)<br/>
34      * Offset to set
35      * @link http://php.net/manual/en/arrayaccess.offsetset.php
36      * @param mixed $offset <p>
37      * The offset to assign the value to.
38      * </p>
39      * @param mixed $value <p>
40      * The value to set.
41      * </p>
42      * @return void
43      */
44     public function offsetSet($offset, $value);
45 
46     /**
47      * (PHP 5 &gt;= 5.0.0)<br/>
48      * Offset to unset
49      * @link http://php.net/manual/en/arrayaccess.offsetunset.php
50      * @param mixed $offset <p>
51      * The offset to unset.
52      * </p>
53      * @return void
54      */
55     public function offsetUnset($offset);
56 }

 下面咱們能夠寫一個例子,很是簡單:composer

 1 <?php
 2 class Test implements ArrayAccess
 3 {
 4     private $testData;
 5 
 6     public function offsetExists($key)
 7     {
 8         return isset($this->testData[$key]);
 9     }
10 
11     public function offsetSet($key, $value)
12     {
13         $this->testData[$key] = $value;
14     }
15 
16     public function offsetGet($key)
17     {
18         return $this->testData[$key];
19     }
20 
21     public function offsetUnset($key)
22     {
23         unset($this->testData[$key]);
24     }
25 }
26 
27   $obj = new Test();
28 
29   //自動調用offsetSet方法
30   $obj['data'] = 'data';
31 
32   //自動調用offsetExists
33   if(isset($obj['data'])){
34     echo 'has setting!';
35   }
36   //自動調用offsetGet
37   var_dump($obj['data']);
38 
39   //自動調用offsetUnset
40   unset($obj['data']);
41   var_dump($test['data']);
42 
43   //輸出:
44   //has setting!
45   //data  
46   //null

  好了,下面咱們會結合Slim框架來講在實際中的應用,在Slim中使用很是重要,也很是出色的使用了 container,container繼承自Pimple\Container,說到這,就有必要說一下Pimple,pimple是php社區中比較流行的一種ioc容器,pimple中的container類使用了依賴注入的方式來實現實現了程序間的低耦合,能夠用composer添加 require  "pimple/pimple": "1.*" 添加Pimple到依賴類庫,Pimple仍是要多看看的,就一個文件,在程序整個生命週期中,各類屬性、方法、對象、閉包均可以註冊其中,但pimple只是實現了一個容器的概念,還有好多依賴注入、自動建立、關聯等功能須要看Laravel才能深入學到。框架

  在Slim中它使用 container 的類實現了將配置文件依次加載,能夠像訪問數組同樣訪問他們,包括displayErrorDetails,renderer, logger,httpVersion,responseChunkSize,outputBuffering,determineRouteBeforeAppMiddleware,displayErrorDetails等等,使他們在框架加載的時候首先被加載。使用的時候直接取就能夠了,ide

下面就是這種加載機制:學習

<?php

namespace Slim;

use Interop\Container\ContainerInterface;
use Interop\Container\Exception\ContainerException;
use Pimple\Container as PimpleContainer;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Slim\Exception\ContainerValueNotFoundException;

class Container extends PimpleContainer implements ContainerInterface
{
    /**
     * Default settings
     *
     * @var array
     */
    private $defaultSettings = [
        'httpVersion' => '1.1',
        'responseChunkSize' => 4096,
        'outputBuffering' => 'append',
        'determineRouteBeforeAppMiddleware' => false,
        'displayErrorDetails' => false,
    ];

    /**
     * Create new container
     *
     * @param array $values The parameters or objects.
     */
    public function __construct(array $values = [])
    {
        //var_dump($values);          exit;
        parent::__construct($values);

        $userSettings = isset($values['settings']) ? $values['settings'] : [];
        $this->registerDefaultServices($userSettings);
    }

    private function registerDefaultServices($userSettings)
    {
        $defaultSettings = $this->defaultSettings;

        $this['settings'] = function () use ($userSettings, $defaultSettings) {
            return new Collection(array_merge($defaultSettings, $userSettings));
        };
        
        $defaultProvider = new DefaultServicesProvider();
        $defaultProvider->register($this);
    }
  
    . . .

}

其中 defaultSettings 爲系統默認配置,userSettings爲用戶的配置,好比日誌,模板等。網站

下面這段是offsetGet,巧妙使用鍵值來判斷該值是否已經設置過,若是設置過就會直接去取了,沒有設置就會轉到設置的邏輯。

 1     public function offsetGet($id)
 2     {
 3         if (!isset($this->keys[$id])) {
 4             throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
 5         }
 6 
 7         if (
 8             isset($this->raw[$id])
 9             || !is_object($this->values[$id])
10             || isset($this->protected[$this->values[$id]])
11             || !method_exists($this->values[$id], '__invoke')
12         ) {
13             return $this->values[$id];
14         }
15 
16         if (isset($this->factories[$this->values[$id]])) {
17             return $this->values[$id]($this);
18         }
19 
20         $raw = $this->values[$id];
21         $val = $this->values[$id] = $raw($this);
22         $this->raw[$id] = $raw;
23 
24         $this->frozen[$id] = true;
25 
26         return $val;
27     }

咱們再看看 PimpleContainer,以下圖:

     咱們能夠看到其中有個 SplObjectStorage,須要說一下這個,SplObjectStorage是用來存儲一組對象,當你須要惟一標識對象的時候。按照官網的說法 PHP SPL SplObjectStorage類實現了Countable, Iterator, Serializable, ArrayAccess四個接口,可實現統計、迭代、序列化、數組式訪問等功能。因此SplObjectStorage是一個標準的對象容器。

  說到這你們對ArrayAccess應該有所瞭解了,若是還不清楚,能夠多看看Slim的源碼,上面寫的比較清楚,並且那套源碼及其的簡練,值得咱們學習。

      博客會同步更新到個人我的網站,歡迎你們訪問!

注意:
一、本博客同步更新到個人我的網站:http://www.zhaoyafei.cn
二、本文屬原創內容,爲了尊重他人勞動,轉載請註明本文地址:
http://www.cnblogs.com/zyf-zhaoyafei/p/5228652.html
相關文章
相關標籤/搜索