简体   繁体   English

在没有容器数组的情况下为 ArrayAccess 实现 Iterator 接口

[英]Implement Iterator interface for ArrayAccess without container array

This is my attempt at implementing https://www.php.net/manual/en/class.iterator.php for an ArrayAccess.这是我为 ArrayAccess 实现https://www.php.net/manual/en/class.iterator.php的尝试。 Many examples use a container array as a private member variable;许多示例使用容器数组作为私有成员变量; but I do not want to use a container array if possible.但如果可能的话,我不想使用容器数组。 The main reason why I don't want a container array is because I'd like to access the property (array key) like this $DomainData->domainId all while having intellisense, etc.我不想要容器数组的主要原因是因为我想在拥有智能感知等的同时访问像$DomainData->domainId这样的属性(数组键)。

Demo: https://ideone.com/KLPwwY演示: https : //ideone.com/KLPwwY

class DomainData implements ArrayAccess, Iterator
{
    private $position = 0;
    public $domainId;
    public $color;

    public function __construct($data = array())
    {
        $this->position = 0;
        foreach ($data as $key => $value) {
            $this[$key] = $value;
        }
    }

    public function offsetExists($offset)
    {
        return isset($this->$offset);
    }

    public function offsetSet($offset, $value)
    {
        $this->$offset = $value;
    }

    public function offsetGet($offset)
    {
        return $this->$offset;
    }

    public function offsetUnset($offset)
    {
        $this->$offset = null;
    }

    /*****************************************************************/
    /*                     Iterator Implementation                   */
    /*****************************************************************/

    public function rewind()
    {
        $this->position = 0;
    }

    public function current()
    {
        return $this[$this->position];
    }

    public function key()
    {
        return $this->position;
    }

    public function next()
    {
        ++$this->position;
    }

    public function valid()
    {
        return isset($this[$this->position]);
    }
}

Calling it:调用它:

$domainData = new DomainData([
    "domainId" => 1,
    "color" => "red"
]);

var_dump($domainData);

foreach($domainData as $k => $v){
    var_dump("domainData[$k] = $v");
}

actual:实际的:

object(DomainData)#1 (3) {
  ["position":"DomainData":private]=>
  int(0)
  ["domainId"]=>
  int(1)
  ["color"]=>
  string(3) "red"
}

desired:期望:

object(DomainData)#1 (3) {
  ["position":"DomainData":private]=>
  int(0)
  ["domainId"]=>
  int(1)
  ["color"]=>
  string(3) "red"
}
string(24) "domainData[domainId] = 1"
string(23) "domainData[color] = red"

Let me describe a couple of ways of how you could do this.让我描述一下您如何做到这一点的几种方法。

ArrayObject with custom code带有自定义代码的 ArrayObject

ArrayObject implements all of the interfaces that you want. ArrayObject实现了您想要的所有接口。

class DomainData extends ArrayObject
{
  public $domainId;
  public $color;

  public function __construct($data = array())
  {
    parent::__construct($data);
    foreach ($data as $key => $value) {
      $this->$key = $value;
    }
  }
}

This isn't very nice, though;不过,这不是很好。 it copies the keys and values twice, and changing a property doesn't change the underlying array.它复制键和值两次,更改属性不会更改底层数组。

Implement IteratorAggregate on get_object_vars()在 get_object_vars() 上实现 IteratorAggregate

If you don't mind giving up on ArrayAccess , you could get away with only implementing an aggregate iterator .如果你不介意放弃ArrayAccess ,你可以只实现一个聚合迭代器

class DomainData implements IteratorAggregate
{
    public $domainId;
    public $color;

    public function __construct($data = [])
    {
        foreach ($data as $key => $value) {
            $this->$key = $value;
        }
    }

    public function getIterator()
    {
        return new ArrayIterator(get_object_vars($this));
    }
}

ArrayObject with property flag and doc blocks带有属性标志和文档块的 ArrayObject

A better way would be to use doc blocks for describing your properties (described here ), and then use the ARRAY_AS_PROPS flag to expose the array as properties.更好的方法是使用 doc 块来描述您的属性( 在此处描述),然后使用ARRAY_AS_PROPS标志将数组公开为属性。

/**
 * Magic class
 * @property int $domainId
 * @property string $color
 */
class DomainData extends ArrayObject
{
  function __construct($data = []) {
    parent::__construct($data, parent::ARRAY_AS_PROPS);
  }
}

When loaded inside PhpStorm, you'd see this:在 PhpStorm 中加载时,您会看到: phpstorm 编辑器

Please try get_object_vars() php function to Gets the accessible non-static properties of the given object according to scope.请尝试get_object_vars() php 函数根据范围获取给定对象的可访问非静态属性。

The function adds before foreach loop.该函数在foreach循环之前添加。 It's working.它正在工作。

$domainData = get_object_vars($domainData);
foreach($domainData as $k => $v){
    var_dump("domainData[$k] = $v");
}

=> Output => 输出

string(24) "domainData[domainId] = 1"
string(23) "domainData[color] = red"

Implement Iterator interface for ArrayAccess for example例如,为 ArrayAccess 实现 Iterator 接口

<?php

/**
 * Class Collection
 * @noinspection PhpUnused
 */
class Collection implements ArrayAccess, IteratorAggregate, JsonSerializable, Countable
{
    /**
     * @var array $collection
     */
    private array  $collection;

    /**
     * @inheritDoc
     */
    public function offsetExists($offset): bool
    {
        return isset($this->collection[$offset]);
    }

    /**
     * @inheritDoc
     */
    public function offsetGet($offset)
    {
        return $this->collection[$offset];
    }

    /**
     * @inheritDoc
     */
    public function offsetSet($offset, $value)
    {
        if (empty($offset)) {
            return $this->collection[] = $value;
        }

       return $this->collection[$offset] = $value;

    }

    /**
     * @inheritDoc
     */
    public function offsetUnset($offset): void
    {
        unset($this->collection[$offset]);
    }



    /**
     * @inheritDoc
     */
    public function jsonSerialize()
    {
        return serialize($this->collection);
    }

    /**
     * @inheritDoc
     */
    public function count()
    {
        return count($this->collection);
    }

    /**
     * @return array
     */
    public function __debugInfo()
    {
        return $this->collection;
    }


    /**
     * @return mixed
     */
    public function first()
    {
        return $this->collection[0];
    }

    /**
     * @inheritDoc
     */
    public function getIterator()
    {
        return new ArrayIterator($this->collection);
    }

    /** @noinspection MagicMethodsValidityInspection */
    public function __toString()
    {
        return json_encode($this->collection, JSON_THROW_ON_ERROR, 512);
    }

    /**
     * @return mixed
     */
    public function last()
    {
        return $this->collection[$this->count()-1];
    }

}

for example using例如使用

<?php

$collections = new Collection();

$collections[] =12;

$collections[] = 14;
$collections[] = 145;
$collections[] =4;


print_r($collections);


echo $collections;

echo $collections->last();

echo $collections->first();

foreach ($collections as $collection)
{
    echo $collection;
}

count($collections);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM