一、简介

  PHP最基本的预定义接口一共有6个,分别是:TraversableIteratorIteratorAggregateArrayAccessSerializableClosure;其中最常用、也是最重量级的就是ArrayAccess了,该接口的作用是提供像访问数组一样访问
对象的能力;接口的出现频率最高,特别是在框架中用得也最多,比如Laravel、Symfony2等都有用到,用的也是灵活巧妙;下面将举例介绍该接口的使用方法。

二、用法

ArrayAccess 在 PHP5 中才开始有的,PHP5 中添加了一系列接口,这些接口和实现的 Class 统称为 SPL(PHP 标准库)。
接口摘要如下:

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

我们在使用ArrayAccess接口的时候,需要实现以上四个方法,再看看接口的原型如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* Interface to provide accessing objects as arrays.
* @link http://php.net/manual/en/class.arrayaccess.php
*/
interface ArrayAccess {

/**
* Whether a offset exists
* @link http://php.net/manual/en/arrayaccess.offsetexists.php
* @param mixed $offset <p>
* An offset to check for.
* </p>
* @return boolean true on success or false on failure.
* </p>
* <p>
* The return value will be casted to boolean if non-boolean was returned.
* @since 5.0.0
*/
public function offsetExists($offset);

/**
* Offset to retrieve
* @link http://php.net/manual/en/arrayaccess.offsetget.php
* @param mixed $offset <p>
* The offset to retrieve.
* </p>
* @return mixed Can return all value types.
* @since 5.0.0
*/
public function offsetGet($offset);

/**
* Offset to set
* @link http://php.net/manual/en/arrayaccess.offsetset.php
* @param mixed $offset <p>
* The offset to assign the value to.
* </p>
* @param mixed $value <p>
* The value to set.
* </p>
* @return void
* @since 5.0.0
*/
public function offsetSet($offset, $value);

/**
* Offset to unset
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
* @param mixed $offset <p>
* The offset to unset.
* </p>
* @return void
* @since 5.0.0
*/
public function offsetUnset($offset);
}

下面举一个简单例子说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Test implements ArrayAccess
{
private $data;

public function offsetExists($key)
{
return isset($this->data[$key]);
}
public function offsetGet($key)
{
return $this->data[$key];
}
public function offsetSet($key, $value)
{
$this->data[$key] = $value;
}
public function offsetUnset($key)
{
unset($this->data[$key]);
}
}

$test = new Test();
//调用offsetSet方法
$test['data'] = 'MinHow';
//调用offsetExists方法
if (isset($test['data'])) {
print_r('Setting');
}
//调用offsetGet方法
print_r($test['data']);
//调用offsetUnset方法
unset($test['data']);
print_r($test['data']);

//忽略警告的情况下输出:
//Setting
//MinHow
//null

在 Laravel 框架中也有应用该接口,尤其在框架最核心的 IOC 容器中就有使用到,可以查看 Container.php 源码文件,下面是简写版的容器类源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//判断 bindings[$key] 是否存在,例:isset($container['data'])
public function offsetExists($key)
{
return isset($this->bindings[$key]);
}

//取得实例化对象,调用 make() 方法,例:$container['data']
public function offsetGet($key)
{
return $this->make($key);
}

//设置对象,例:$container['data'] = $value
public function offsetSet($key, $value)
{
// 如果 $value 不是闭包函数,就先将 $value 重新赋值为一个闭包
if (! $value instanceof Closure) {
$value = function () use ($value) {
return $value;
};
}
// 如果 $value 是一个闭包函数,就直接绑定
$this->bind($key, $value);
}

//释放 bindings[$key],例:unset($container['data'])
public function offsetUnset($key)
{
unset($this->bindings[$key]);
}

完整的容器类文件在[laravel-container]上。
下面是结合容器类的测试案例,测试文件源码[test.php]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
/**
* User: MinHow
* Date: 2017/12/29
* Time: 22:36
*/
//引入Container容器类
require '../Container.php';

$app = new Container();//实例化容器
//调用offsetSet方法
$app['test'] = 'MinHow';

//调用offsetExists方法
if (isset($app['test'])) {
print_r('Using offsetExists');
}
//调用offsetGet方法
print_r($app['test']);

//调用offsetUnset方法
unset($app['test']);

//输出:
//Using offsetExists
//MinHow

  • 当执行$app['test'] = 'MinHow'的时候,会调用offsetSet方法,该方法会返回一个闭包函数并保存到容器中;
  • 当执行isset($app['test'])的时候,调用offsetExists方法,判断容器中是否存在该变量;
  • 当执行print_r($app['test'])的时候,调用offsetGet方法,从容器中解析函数,因为第一步已经生产了一个闭包函数,所以直接返回执行的方法。
  • 当执行unset($app['test'])的时候;调用offsetUnset方法,释放容器中的值。

更多 Laravel 容器类的讲解,可以查看我之前写的[浅析 Laravel IOC 容器]文章。

三、总结

讲解到这里,大家应该对ArrayAccess有了初步的认识,更多的深入运用案例,可以多看看 Laravel 源码,非常值得我们深入学习。

最后更新: 2018年01月06日 16:29

原始链接: http://blog.minhow.com/articles/php/predefine-arrayaccess/

× 请我吃糖~
打赏二维码