开发笔记📐 发现👽 人物👮 趣闻💦
PHP预定义接口之ArrayAccess 使你的对象可以像数组一样访问

PHP预定义接口之ArrayAccess 使你的对象可以像数组一样访问
2018-06-09 09:27:05   点击:

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)

     * Whether a offset exists
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
     * @param mixed $offset


     * An offset to check for.
     *


     * @return boolean true on success or false on failure.
     *

 


     *


     * The return value will be casted to boolean if non-boolean was returned.
     */
    public function offsetExists($offset);

    /**
     * (PHP 5 >= 5.0.0)

     * Offset to retrieve
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
     * @param mixed $offset


     * The offset to retrieve.
     *


     * @return mixed Can return all value types.
     */
    public function offsetGet($offset);

 

    /**
     * (PHP 5 >= 5.0.0)

     * Offset to set
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
     * @param mixed $offset


     * The offset to assign the value to.
     *


     * @param mixed $value


     * The value to set.
     *


     * @return void
     */
    public function offsetSet($offset, $value);

 

    /**
     * (PHP 5 >= 5.0.0)

     * Offset to unset
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
     * @param mixed $offset


     * The offset to unset.
     *


     * @return void
     */
    public function offsetUnset($offset);
}

 

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

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方法
  $obj['data'] = 'data';

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

下面就是这种加载机制:

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

 原文地址:http://www.cnblogs.com/zyf-zhaoyafei/p/5228652.html

PHP 数组 接口 对象

上一篇:搬运:详解CSS清浮动处理(Clear与BFC)
下一篇:搬运:HTTP协议详解 URL|请求|响应|报头