PHP预定义接口之 ArrayAccess

  最近这段时间回家过年了,博客也没有更新,感觉少学习了好多东西,也错失了好多的学习机会,就像大家在春节抢红包时常说的一句话:一不留神错过了好几亿。废话少说,这篇博客给大家说说关于PHP预定义接口中常用到的重量级人物: ArrayAccess。大家也许会问,最基本、最常用的预定义接口有6个呢,为啥非得说这个。从日常的使用情况来看:这个出现的频率非常高,特别是在框架中,比如Laravel、Slim等都会用到,并且用得非常经典,让人佩服啊。从技术上说:说实话其他的我用的少啊!只是知道简单的用法,对他的理解比较浅显,不敢在这里误导大家,哈哈!今天我要写的内容也不一定都正确,不对之处还请指正。

ArrayAccess

  先说 ArrayAccess 吧!ArrayAccess 的作用是使得你的对象可以像数组一样可以被访问。应该说 ArrayAccess 在PHP5中才开始有的,PHP5中加入了很多新的特性,当然也使类的重载也加强了,PHP5 中添加了一系列接口,这些接口和实现的 Class 统称为 SPL。

ArrayAccess 这个接口定义了4个必须要实现的方法:

{
   abstract public offsetExists ($offset)  //检查偏移位置是否存在
   abstract public offsetGet ($offset)     //获取一个偏移位置的值
   abstract public void offsetSet ($offset ,$value) //设置一个偏移位置的值
   abstract public void offsetUnset ($offset)       //复位一个偏移位置的值
}

所以我们要使用ArrayAccess这个接口,就要实现相应的方法,这几个方法不是随便写的,我们可以看一下 ArrayAccess 的原型:

 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 }

下面我们可以写一个例子,非常简单:

 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等等,使他们在框架加载的时候首先被加载。使用的时候直接取就可以了,

下面就是这种加载机制:

<?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的源码,上面写的比较清楚,而且那套源码及其的简练,值得我们学习。

转载请注明出处,后面会持续更新,谢谢大家!

时间: 2024-10-05 13:00:43

PHP预定义接口之 ArrayAccess的相关文章

复习PHP-语言参考-预定义接口

1.Traversable 他是一个遍历接口规范 注意:发现一个有用的函数get_declared_classes,可以以数组形式显示当前脚本下所有已经定义的类名 2.Iterator Iterator迭代器继承自Traversable,是一种遍历对象内容的对象. 你可以自己写一个子类继承自它,并写上具体遍历的方法. Iterator包含:current(返回当前元素),key(当前键),next(下一个元素),rewind(返回至初始元素),valid(检测当前元素是否存在)五种方法. 3.I

PHP预定义接口中 ArrayAccess 数组式访问接口

<?php class obj implements arrayaccess { private $container = array(); public function __construct () { $this -> container = array( "one" => 1 , "two" => 2 , "three" => 3 , ); } public function offsetSet ( $off

预定义接口

迭代器:可在内部迭代自己的外部迭代器或类的接口. Iterator::current/key/next/rewind/valid. 用foreach调用迭代器方法时的顺序: 聚合式迭代器:创建外部迭代器的接口. 数组式访问: ArrayAccess::offsetExists 检测一个偏移位置是否存在 ArrayAccess::offsetGet 获取一个偏移位置的值 ArrayAccess::offsetSet 设置一个偏移位置的值 ArrayAccess::offsetUnset 复位一个偏

PHP预定义接口一:Traversable

Traversable用于检测一个类是否可以使用 foreach 进行遍历. 这是一个无法在 PHP 脚本中实现的内部引擎接口,实际编程中我们使用Iterator接口或者IteratorAggregate接口来实现遍历. 这个接口没有任何方法,它的作用仅仅是作为所有可遍历类的基本接口. 接口摘要 Traversable { } 代码演示: $arr = [1, 2, 3, 4]; $obj = (object)$arr; if ($arr instanceof \Traversable) { e

php预定义接口中迭代的执行流程

<?php class myIterator implements Iterator { private $position = 0 ; private $array = array( "firstelement" , "secondelement" , "lastelement" , ); public function __construct () { $this -> position = 0 ; } //第一步 functio

【struts2】预定义拦截器

1)预定义拦截器 Struts2有默认的拦截器配置,也就是说,虽然我们没有主动去配置任何关于拦截器的东西,但是Struts2会使用默认引用的拦截器.由于Struts2的默认拦截器声明和引用都在这个Struts-default.xml里面,因此我们需要到这个文件的struts-default包里去看一下.定义如下: 1 <interceptors> 2 <interceptor name="alias" class="com.opensymphony.xwor

PHP魔术函数、魔术常量、预定义常量

一.魔术函数(13个) 1.__construct() 实例化对象时被调用, 当__construct和以类名为函数名的函数同时存在时,__construct将被调用,另一个不被调用. 2.__destruct() 当删除一个对象或对象操作终止时被调用. 3.__call() 对象调用某个方法, 若方法存在,则直接调用:若不存在,则会去调用__call函数. 4.__get() 读取一个对象的属性时,若属性存在,则直接返回属性值: 若不存在,则会调用__get函数. 5.__set() 设置一个

Attribute(一)——预定义特性

在项目中接触到了Attribute,那么什么是Attribute,有些什么作用呢?这里来了解一下. 一.什么是Attribute Attribute 类将预定义的系统信息或用户定义的自定义信息与目标元素相关联.目标元素可以是程序集.类.构造函数.委托.枚举.事件.字段.接口.方法.可移植可执行文件模块.参数.属性 (Property).返回值.结构或其他属性 (Attribute) 在这里,我们需要将Attribute和property分开 property是指类想外提供的字段,它属于面向对象层

Visual Studio 2012 预定义数据类型

预定义数据类型 一.值类型 整型:(整数) 有符号整型和无符号整形,区别是有符号的有负数无符号的都是正数, 2x+1 常用int 有符号:              带有正负数,范围为按所写依次增大 Sbyte   -128到127    有符号8位整数 short    -32,768 到 32,767    有符号16位整数 int     -2,147,483,648 到 2,147,483,647     有符号 32 位整数 long   -9,223,372,036,854,775,