Loading...
赵亚飞
Copyright zyf @2014-2017
京ICP备16012237号-2
文章详情

PHP预定义接口之 ArrayAccess

2016-03-01 09:56 
4691 
0

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

ArrayAccess

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

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

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

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

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

  1. <?php
  2. class Test implements ArrayAccess
  3. {
  4. private $testData;
  5. public function offsetExists($key)
  6. {
  7. return isset($this->testData[$key]);
  8. }
  9. public function offsetSet($key, $value)
  10. {
  11. $this->testData[$key] = $value;
  12. }
  13. public function offsetGet($key)
  14. {
  15. return $this->testData[$key];
  16. }
  17. public function offsetUnset($key)
  18. {
  19. unset($this->testData[$key]);
  20. }
  21. }
  22. $obj = new Test();
  23. //自动调用offsetSet方法
  24. $obj['data'] = 'data';
  25. //自动调用offsetExists
  26. if(isset($obj['data'])){
  27. echo 'has setting!';
  28. }
  29. //自动调用offsetGet
  30. var_dump($obj['data']);
  31. //自动调用offsetUnset
  32. unset($obj['data']);
  33. var_dump($test['data']);
  34. //输出:
  35. //has setting!
  36. //data
  37. //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 等等,使他们在框架加载的时候首先被加载。使用的时候直接取就可以了,下面就是这种加载机制:

  1. <?php
  2. namespace Slim;
  3. use Interop\Container\ContainerInterface;
  4. use Interop\Container\Exception\ContainerException;
  5. use Pimple\Container as PimpleContainer;
  6. use Psr\Http\Message\ResponseInterface;
  7. use Psr\Http\Message\ServerRequestInterface;
  8. use Slim\Exception\ContainerValueNotFoundException;
  9. class Container extends PimpleContainer implements ContainerInterface
  10. {
  11. /**
  12. * Default settings
  13. *
  14. * @var array
  15. */
  16. private $defaultSettings = [
  17. 'httpVersion' => '1.1',
  18. 'responseChunkSize' => 4096,
  19. 'outputBuffering' => 'append',
  20. 'determineRouteBeforeAppMiddleware' => false,
  21. 'displayErrorDetails' => false,
  22. ];
  23. /**
  24. * Create new container
  25. *
  26. * @param array $values The parameters or objects.
  27. */
  28. public function __construct(array $values = [])
  29. {
  30. //var_dump($values); exit;
  31. parent::__construct($values);
  32. $userSettings = isset($values['settings']) ? $values['settings'] : [];
  33. $this->registerDefaultServices($userSettings);
  34. }
  35. private function registerDefaultServices($userSettings)
  36. {
  37. $defaultSettings = $this->defaultSettings;
  38. $this['settings'] = function () use ($userSettings, $defaultSettings) {
  39. return new Collection(array_merge($defaultSettings, $userSettings));
  40. };
  41. $defaultProvider = new DefaultServicesProvider();
  42. $defaultProvider->register($this);
  43. }
  44. . . .
  45. }

其中 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. if (
  7. isset($this->raw[$id])
  8. || !is_object($this->values[$id])
  9. || isset($this->protected[$this->values[$id]])
  10. || !method_exists($this->values[$id], '__invoke')
  11. ) {
  12. return $this->values[$id];
  13. }
  14. if (isset($this->factories[$this->values[$id]])) {
  15. return $this->values[$id]($this);
  16. }
  17. $raw = $this->values[$id];
  18. $val = $this->values[$id] = $raw($this);
  19. $this->raw[$id] = $raw;
  20. $this->frozen[$id] = true;
  21. return $val;
  22. }

我们再看看 PimpleContainer,如下图:

  我们可以看到其中有个 SplObjectStorage,需要说一下这个,SplObjectStorage是用来存储一组对象,当你需要唯一标识对象的时候。按照官网的说法 PHP SPL SplObjectStorage类实现了Countable, Iterator, Serializable, ArrayAccess四个接口,可实现统计、迭代、序列化、数组式访问等功能。所以SplObjectStorage是一个标准的对象容器。

  说到这大家对ArrayAccess应该有所了解了,如果还不清楚,可以多看看Slim的源码,上面写的比较清楚,而且那套源码及其的简练,值得我们学习。 博客会同步更新到我的个人网站 zhaoyafei.cn,欢迎大家访问!

评论列表

握草,你的大括号怎么变成java风格的了

添加评论






点击切换

提交评论