为没有容器数组的 ArrayAccess 实现 Iterator 接口
Implement Iterator interface for ArrayAccess without container array
这是我为 ArrayAccess 实现 https://www.php.net/manual/en/class.iterator.php 的尝试。许多示例使用容器数组作为私有成员变量;但如果可能的话,我不想使用容器数组。我不想要容器数组的主要原因是因为我想像这样 $DomainData->domainId
访问 属性 (数组键),同时具有智能感知等
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"
请尝试 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"
让我描述一下您可以如何做到这一点的几种方法。
带有自定义代码的 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 中时,您会看到:
例如为 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);
这是我为 ArrayAccess 实现 https://www.php.net/manual/en/class.iterator.php 的尝试。许多示例使用容器数组作为私有成员变量;但如果可能的话,我不想使用容器数组。我不想要容器数组的主要原因是因为我想像这样 $DomainData->domainId
访问 属性 (数组键),同时具有智能感知等
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"
请尝试 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"
让我描述一下您可以如何做到这一点的几种方法。
带有自定义代码的 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 中时,您会看到:
例如为 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);