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 的原型:
/**
* Interface to provide accessing objects as arrays.
* @link http://php.net/manual/en/class.arrayaccess.php
*/
interface ArrayAccess { /**
* (PHP 5 >= 5.0.0)<br/>
* 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.
*/
public function offsetExists($offset); /**
* (PHP 5 >= 5.0.0)<br/>
* 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.
*/
public function offsetGet($offset); /**
* (PHP 5 >= 5.0.0)<br/>
* 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
*/
public function offsetSet($offset, $value); /**
* (PHP 5 >= 5.0.0)<br/>
* Offset to unset
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
* @param mixed $offset <p>
* The offset to unset.
* </p>
* @return void
*/
public function offsetUnset($offset);
}
下面我们可以写一个例子,非常简单:
<?php
class Test implements ArrayAccess
{
private $testData; public function offsetExists($key)
{
return isset($this->testData[$key]);
} public function offsetSet($key, $value)
{
$this->testData[$key] = $value;
} public function offsetGet($key)
{
return $this->testData[$key];
} public function offsetUnset($key)
{
unset($this->testData[$key]);
}
} $obj = new Test(); //自动调用offsetSet方法
30 $obj['data'] = 'data'; //自动调用offsetExists
33 if(isset($obj['data'])){
echo 'has setting!';
}
//自动调用offsetGet
var_dump($obj['data']); //自动调用offsetUnset
unset($obj['data']);
var_dump($test['data']); //输出:
//has setting!
//data
//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,巧妙使用键值来判断该值是否已经设置过,如果设置过就会直接去取了,没有设置就会转到设置的逻辑。
public function offsetGet($id)
{
if (!isset($this->keys[$id])) {
throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
} if (
isset($this->raw[$id])
|| !is_object($this->values[$id])
|| isset($this->protected[$this->values[$id]])
|| !method_exists($this->values[$id], '__invoke')
) {
return $this->values[$id];
} if (isset($this->factories[$this->values[$id]])) {
return $this->values[$id]($this);
} $raw = $this->values[$id];
$val = $this->values[$id] = $raw($this);
$this->raw[$id] = $raw; $this->frozen[$id] = true; return $val;
}
我们再看看 PimpleContainer,如下图:
我们可以看到其中有个 SplObjectStorage,需要说一下这个,SplObjectStorage是用来存储一组对象,当你需要唯一标识对象的时候。按照官网的说法 PHP SPL SplObjectStorage类实现了Countable, Iterator, Serializable, ArrayAccess四个接口,可实现统计、迭代、序列化、数组式访问等功能。所以SplObjectStorage是一个标准的对象容器。
说到这大家对ArrayAccess应该有所了解了,如果还不清楚,可以多看看Slim的源码,上面写的比较清楚,而且那套源码及其的简练,值得我们学习。
博客会同步更新到我的个人网站,欢迎大家访问!
PHP预定义接口之 ArrayAccess的更多相关文章
- 深入理解 PHP 的 7 个预定义接口
深入理解预定义接口 场景:平常工作中写的都是业务模块,很少会去实现这样的接口,但是在框架里面用的倒是很多. 1. Traversable(遍历)接口 该接口不能被类直接实现,如果直接写了一个普通类 ...
- 深入理解PHP数组函数和预定义接口
一. PHP对数组的过滤 函数: array_filter(p1[,p2]) 参数p1是要过滤的数组,参数p2是自定义过滤会掉函数(可以是匿名函数) 例子: <?php $arr = ['',n ...
- PHP预定义接口
目录 引言 IteratorAggregate(聚合式aggregate迭代器Iterator) Countable ArrayAccess Iterator 总结 引言 在PHP中有好几个预定义的接 ...
- PHP Predefined Interfaces 预定义接口(转)
SPL提供了6个迭代器接口: Traversable 遍历接口(检测一个类是否可以使用 foreach 进行遍历的接口) Iterator 迭代器接口(可在内部迭代自己的外部迭代器或类的接口) Ite ...
- PHP Predefined Interfaces 预定义接口
SPL提供了6个迭代器接口: Traversable 遍历接口(检测一个类是否可以使用 foreach 进行遍历的接口) Iterator 迭代器接口(可在内部迭代自己的外部迭代器或类的接口) Ite ...
- 预定义接口-迭代器Iterator
<?php /* 可在内部迭代自己的外部迭代器或类的接口. Iterator extends Traversable { abstract public mixed current ( void ...
- php 预定义接口
Traversable Traversable { } 作用:检测一个类是否可以使用 foreach 进行遍历的接口. php代码中不能用.只有内部的PHP类(用C写的类)才可以直接实现Travers ...
- Java8学习笔记(二)--三个预定义函数接口
三个函数接口概述 JDK预定义了很多函数接口以避免用户重复定义.最典型的是Function: @FunctionalInterface public interface Function<T, ...
- 20141009---Visual Studio 2012 预定义数据类型
预定义数据类型 一.值类型 整型:(整数) 有符号整型和无符号整形,区别是有符号的有负数无符号的都是正数, 2x+1 常用int 有符号: 带有正负数,范围为按所写依次增大 ...
随机推荐
- Jenkins 安装FAQ
1.对路径的访问被拒绝,如: 解决办法:以管理员模式进入DOS命令窗口,参考Jenkins安装中的第4步: 2.服务不能启动,提示: 解决办法:启动Windows Service(InstallU ...
- Jmeter插件监控服务器性能
处理利用jmeter实施监控压测时受压机的各项性能 操作步骤: 施压机上的jmeter/lib/ext中放入下载的插件包 jmeter-plugins-perfmon-2.1.jar 受压机上放入Se ...
- 2016 年 11 月 12 个轻量级的 JavaScript 库
https://www.oschina.net/news/79316/2016-11-javascript-library?from=20161127
- checkbox做全选按钮
1.先写一个html页面,里面写一个全选按钮和几个复选框,实现下面2个要求 (1)点击全选按钮选中时,所有的复选框选中. (2)点击全选按钮取消选中时,所有复选框取消选中. <input typ ...
- CSS--background
它的组合写法: background-color, background-image, background-repeat,backgroundattachment, background-posit ...
- 《你不常用的c#之XX》
你不常用的c#之一>:略谈unsafe http://blog.csdn.net/robingaoxb/article/details/6199508 <你不常用的c#之二>:略谈G ...
- ORA-01722:无效数字
今天写查询语句,关联多张表,出现了这个错误. 结果发现时字段的数据类型不一致. select * from table_a a,table_b b where to_char(a.project_id ...
- AssetBundle
AssetBundle是Unity推荐的一种资源打包方式,与不使用AssetBundle相比,它有如下优点: 1.AssetBundle是经过LZMA压缩过的,所以体积更小. 2.可以将AssetBu ...
- 解决Myeclipse PermGen space问题
myeclipse配置web服务器配置 Window—Preferences—Myeclipse—Servers—tomcat JDK的Optional Java VM arguments配置为:-X ...
- 【错误总结】java.lang.NoClassDefFoundError: org/objectweb/asm/ClassVisitor
运行环境 JDK1.7 64位 Window 7 64位 Ecplise Java EE IDE Struts 2.3.9 Tomcat 7 说明: ...