【问题标题】:Implement Iterator interface for ArrayAccess without container array为没有容器数组的 ArrayAccess 实现 Iterator 接口
【发布时间】:2020-06-26 14:29:05
【问题描述】:

这是我为 ArrayAccess 实现 https://www.php.net/manual/en/class.iterator.php 的尝试。许多示例使用容器数组作为私有成员变量;但如果可能的话,我不想使用容器数组。我不想要容器数组的主要原因是因为我想在拥有智能感知等的同时访问像 $DomainData->domainId 这样的属性(数组键)。

演示: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]);
    }
}

调用它:

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

var_dump($domainData);

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

实际:

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

想要的:

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"

【问题讨论】:

    标签: php arrays iterator php-5.6 arrayaccess


    【解决方案1】:

    请尝试get_object_vars() php函数根据范围获取给定对象的可访问非静态属性。

    函数在foreach 循环之前添加。它正在工作。

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

    => 输出

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

    【讨论】:

      【解决方案2】:

      让我描述一下如何做到这一点的几种方法。

      带有自定义代码的ArrayObject

      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;
          }
        }
      }
      

      不过,这不是很好;它复制键和值两次,更改属性不会更改底层数组。

      在 get_object_vars() 上实现 IteratorAggregate

      如果你不介意放弃ArrayAccess,你可以只实现aggregate iterator

      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

      更好的方法是使用文档块来描述您的属性(描述为here),然后使用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);
        }
      }
      

      在 PhpStorm 中加载时,您会看到:

      【讨论】:

        【解决方案3】:

        例如实现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];
            }
        
        }
        
        

        例如使用

        <?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);
        

        【讨论】:

          猜你喜欢
          • 2019-01-12
          • 2016-05-15
          • 2012-04-15
          • 2015-12-13
          • 1970-01-01
          • 1970-01-01
          • 2014-03-16
          • 2010-12-05
          • 2014-01-01
          相关资源
          最近更新 更多