32

有人可以清楚地解释 PHP和PHP 在功能和操作方面ArrayIterator的根本区别吗?谢谢!ArrayObjectArray

4

7 回答 7

33

Array是原生的 php 类型。您可以使用 php 语言结构创建一个array(),或者从 php 5.4 开始[]

ArrayObject是一个object与数组完全一样的工作。这些可以使用new关键字创建

ArrayIterator就像ArrayObject,但它可以自我迭代。也使用创建new


比较Array与 ( ArrayObject/ ArrayIterator)

它们都可以使用 php 的数组语法,例如。

$array[] = 'foo';
$object[] = 'foo';
// adds new element with the expected numeric key

$array['bar'] = 'foo';
$object['bar'] = 'foo';
// adds new element with the key "bar"

foreach($array as $value);
foreach($object as $value);
// iterating over the elements

但是,它们仍然是对象与数组,因此您会注意到

is_array($array); // true
is_array($object); // false

is_object($array); // false
is_object($object); // true

大多数 php 数组函数都需要数组,因此在其中使用对象会引发错误。有很多这样的功能。例如。

sort($array); // works as expected
sort($object); // Warning: sort() expects parameter 1 to be array, object given in ......

最后,对象可以做你对对象的期望stdClass,即使用对象语法访问公共属性

$object->foo = 'bar'; // works
$array->foo = 'bar'; // Warning: Attempt to assign property of non-object in ....

数组(作为本机类型)比对象快得多。另一方面,ArrayObject&ArrayIterator类定义了某些可以使用的方法,而数组没有这样的东西


比较ArrayObjectArrayIterator

这两者之间的主要区别在于类的方法。

ArrayIterator实现Iterator接口,为它提供与元素迭代/循环相关的方法。ArrayObject有一个方法叫它exchangeArray与另一个交换它的内部数组。实现一个类似的东西ArrayIterator意味着要么创建一个新对象,要么循环遍历键 &unset一个接一个地设置它们,然后一个接一个地设置新数组中的元素。

接下来,由于ArrayObject无法迭代,因此当您在其中使用它时,foreach它会在内部创建一个ArrayIterator对象(与数组相同)。这意味着 php 创建了原始数据的副本,现在有 2 个具有相同内容的对象。这对于大型阵列将被证明是低效的。但是,您可以指定将哪个类用于迭代器,因此您可以在代码中使用自定义迭代器。

于 2014-06-14T22:01:03.457 回答
10

ArrayObject 和数组有些相似。仅仅是对象(或本机类型)的集合。他们有一些你可以调用的不同方法,但主要归结为同一件事。

但是,迭代器完全是另外一回事。迭代器设计模式是一种保护数组(使其仅可读)的方法。让我们看下一个例子:

你有一个有数组的类。您可以使用 addSomethingToMyArray 将项目添加到该数组。但是请注意,我们在将 item 实际添加到数组之前对其进行了一些操作。这可以是任何东西,但是让我们暂时假设为我们要添加到数组中的每个项目触发此方法非常重要。

class A
{
    private $myArray;
    public function returnMyArray()
    {
        return $this->myArray;
    }

    public function addSomethingToMyArray( $item )
    {
        $this->doSomethingToItem( $item ); 
        array_push( $item );
    }
}

问题在于,您在此处通过引用传递数组。这意味着实际使用 returnMyArray 的类会获得真正的 myArray 对象。这意味着除了 A 之外的类可以向该数组添加内容,因此也可以更改 A 中的数组,而无需使用 addSOmethingToMyArray。但是我们需要做一些事情,记得吗?这是一个无法控制其自身内部状态的类的示例。

解决方案是迭代器。我们没有传递数组,而是将数组传递给一个新对象,该对象只能从数组中读取内容。最简单的迭代器是这样的:

<?php

class MyIterator{

    private $array;
    private $index;

    public function __construct( $array )
    {
        $this->array = $array;
    }

    public function hasNext()
    {
        return count( $this->array ) > $this->index;
    }

    public function next()
    {
        $item = $this->array[ $this->index ];
        this->$index++;

        return $item;
    }       
}

?>

如您所见,我无法向给定数组添加新项目,但我确实可以像这样读取数组:

while( $iterator->hasNext() )
    $item = $iterator->next();

现在又只有一种方法可以将项目添加到 A 中的 myArray,即通过 addSomethingToArray 方法。这就是迭代器,它有点像数组周围的外壳,提供称为封装的东西。

于 2014-12-20T10:50:43.163 回答
0

PHP 中的数组实际上是一个有序映射。映射是将值与键相关联的类型。这种类型针对几种不同的用途进行了优化;它可以被视为数组、列表(向量)、哈希表(映射的实现)、字典、集合、堆栈、队列等等。由于数组值可以是其他数组,因此树和多维数组也是可能的。

此类允许对象作为数组工作。

此迭代器允许在迭代数组和对象时取消设置和修改值和键。

当您想多次迭代同一个数组时,您需要实例化 ArrayObject 并让它创建 ArrayIterator 实例,这些实例通过使用 foreach 或手动调用其 getIterator() 方法来引用它。

于 2012-05-08T16:47:38.387 回答
0

array是 PHP 中的八种原始类型之一。尽管它带有很多内置的实用功能,但它们都是程序化的。

ArrayObject和都ArrayIterator允许我们在面向对象程序(OOP)中使数组成为一等公民。

ArrayObject和之间的区别在于ArrayIterator,由于ArrayIterator实现了SeekableIterator接口,你可以$myArray->seek(10);ArrayIterator.

于 2015-10-05T09:08:19.870 回答
0

编辑:忘记在我的答案中解决普通数组..

在您阅读所有这些之前,如果您是 php 新手并且不想做任何棘手的事情,只是存储值以供以后使用,那么只需使用数组原始类型。

$data = [1,2,3,4,5];
//or
$data = array(1,2,3,4,5);

数组是入口点,你应该先习惯使用它们,然后再考虑使用其他的。如果您不了解数组,那么您可能不会了解使用其他数组的好处。(有关数组的教程,请参见https://www.w3schools.com/php/php_arrays.asp。)

否则继续阅读...

我有同样的问题,来到这里后决定花一些时间测试它们,这是我的发现和结论......

首先让我们澄清一下我立即测试的其他人所说的一些事情。

ArrayObject 和 ArrayItterator 不保护数据。两者仍然可以在 for-each 循环中通过引用传递(例如,参见底部)。

两者都为 is_object() 返回 true,都为 is_array() 返回 false,并且都允许将值作为数组直接访问,而不提供对添加值等的保护,并且两者都可以通过引用传递,从而允许在foreach 循环。

$array = new ArrayIterator();
var_dump(is_array($array)); // false
var_dump(is_object($array)); // true
$array[] = 'value one';
var_dump($array[0]);//string(9) "value one"

$array = new ArrayObject();
var_dump(is_array($array)); // false
var_dump(is_object($array)); // true
$array[] = 'value one';
var_dump($array[0]);//string(9) "value one"

可以在它们中的任何一个可用的功能中看到最大的区别。

ArrayIteroator 具有遍历值所需的所有功能,例如 foreach 循环。(foreach 循环将调用 rewind(),valid(),current(),key() 方法)请参阅:https : //www.php.net/manual/en/class.iterator.php概念(较低级别的类文档)。

箭头函数的智能感知建议

虽然 ArrayObject 仍然可以迭代并以相同的方式访问值,但它不提供对指针函数的公共访问。

数组对象的智能感知

Object 有点像在 ArrayItterator 对象周围添加一个包装器,public getIterator ( void ) : ArrayIterator它可以促进内部值的遍历。

如果您确实需要添加的功能,您始终可以从 ArrayObject 获取 ArrayItterator。

如果您有自己的伪 foreach 循环以奇怪的方式遍历并且想要更好的控制而不是仅仅开始结束遍历,则 ArrayItterator 是最佳选择。

当被 foreach 循环迭代时,ArrayItterator 也是覆盖默认数组行为的好选择。例如..

//I originally made to this to solve some problem where generic conversion to XML via a foreach loop was used,
//and I had a special case where a particular API wanted each value to have the same name in the XML.
class SameKey extends ArrayIterator{

    public function key()
    {
        return "AlwaysTheSameKey";
    }
}

$extendedArrayIterator =  new SameKey(['value one','value two','value three']);
$extendedArrayIterator[] = 'another item added after construct';
//according to foreach there all the keys are the same
foreach ($extendedArrayIterator as $key => $value){
    echo "$key: ";//key is always the same
    var_dump($value);
}
//can still be access as array with index's if you need to differentiate the values
for ($i = 0; $i < count($extendedArrayIterator); $i++){
    echo "Index [$i]: ";
    var_dump($extendedArrayIterator[$i]);
}

如果您对迭代器有更高级别的复杂性,例如,ArrayObject 可能是一个不错的选择......

//lets pretend I have many custom classes extending ArrayIterator each with a different behavior..
$O = new ArrayObject(['val1','val2','val3']);
//and I want to change the behavior on the fly dynamically by changing the iterator class
if ($some_condition = true) $O->setIteratorClass(SameKey::class);
foreach ($O as $key => $value){
    echo "$key: ";//AlwaysTheSameKey:
    var_dump($value);
}

一个示例可能是更改同一数据集的输出,例如拥有一组自定义迭代器,它们在遍历同一数据集时将以不同格式返回值。例如...

class AustralianDates extends ArrayIterator{
    public function current()
    {
        return Date('d/m/Y',parent::current());
    }
}
$O = new ArrayObject([time(),time()+37474,time()+37845678]);
//and I want to change the behaviour on the fly dynamically by changing the iterator class
if ($some_condition = true) $O->setIteratorClass(AustralianDates::class);
foreach ($O as $key => $value){
    echo "$key: ";//AlwaysTheSameKey:
    var_dump($value);
}

显然,可能有更好的方法来做这种事情。

简而言之,这些是我可以看到的主要主要优势差异。

ArrayItorator - 控制或扩展和覆盖遍历行为的较低级别的能力。

VS

ArrayObject - 一个数据容器,但能够更改 ArrayIterator 类。

您可能还想检查其他差异,但我想在您广泛使用它们之前,您不会完全掌握它们。

看来这两个对象都可以在 foreach 中通过引用来使用,但在通过 ArrayObject 使用自定义迭代器类时则不能。

//reference test
$I = new ArrayIterator(['mouse','tree','bike']);
foreach ($I as $key => &$value){
    $value = 'dog';
}
var_dump($I);//all values in the original are now 'dog'

$O = new ArrayObject(['mouse','tree','bike']);
foreach ($O as $key => &$value){
    $value = 'dog';
}
var_dump($O);//all values in the original are now 'dog'

$O->setIteratorClass(SameKey::class);
foreach ($O as $key => &$value){//PHP Fatal error:  An iterator cannot be used with foreach by reference
    $value = 'dog';
}
var_dump($O);

建议/结论

使用数组。

如果你想做一些棘手的事情,我建议总是使用 ArrayIterator 开始,如果你想做一些只有 ArrayObject 才能做的特定事情,才继续使用 ArrayObject。

考虑到 ArrayObject 可以使用您在此过程中创建的任何自定义 ArrayIterators,我说这是要采用的逻辑路径。

希望这对您有所帮助,就像它帮助我研究它一样。

于 2019-05-14T03:39:34.943 回答
0

Iterator是一个对象,它使程序员能够遍历容器,特别是列表。各种类型的迭代器通常通过容器的接口提供。

和之间没有太大区别ArrayObjectArray因为它们代表相同的事物,尽管使用不同的对象类型。

ArrayIterator是一个迭代Array-like对象的迭代器,这包括所有实现的对象ArrayAcess和本机Array类型。事实上,当你foreach遍历一个数组时,PHP 会在内部创建ArrayIterator来进行遍历和转换你的代码,让它看起来就像输入了这个,

for( $arrayIterator->rewind(); $arrayIterator->valid(); $arrayIterator-
>next())
{    $key = $arrayIteartor->key();
     $value = $arrayIterator->current();
}

所以你可以看到,每个集合对象都有一个迭代器,除了你定义的集合,你需要定义你自己的迭代器。

于 2017-11-16T07:18:20.690 回答
0

数组是array类型,ArrayObject并且ArrayIterator是内置类,它们的实例是object类型,在语法和使用级别上部分表现得像数组。

对于这些类,我认为可以从它们实现的接口中获得快速的想法:

class ArrayObject implements IteratorAggregate, ArrayAccess, Serializable, Countable {
class ArrayIterator implements SeekableIterator, ArrayAccess, Serializable, Countable {

两个类都实现:

  • ArrayAccess,因此它们支持数组语法来访问值
  • Countable,所以它们支持值的计数,就像数组一样
  • Iterator(虽然以不同的方式),所以它们适合iterable类型并且可以循环使用foreach等等

一种看待它的方法是,类要数组一样工作会遇到很多麻烦。关键是作为类,它们可以扩展和定制。

它们本质上也可以与通常期望Iterator的任何代码互操作,因此基本用例就是这样 - 包装以将数组数据提供给迭代器代码。

所以简而言之ArrayObjectArrayIteratorDo It Yourself数组(两者之间存在一些实现差异)。它们的实例(部分)表现得像array类型,但作为类它们是可扩展的,作为Iterator实现者它们可以与需要的代码互操作。

除非您需要深度自定义的行为和/或Iterator互操作性,否则坚持使用array类型可能是介于两者之间的方式。

值得注意的是,还有一些集合的实现,旨在通过更友好的抽象来提供类的好处。

于 2022-02-06T19:40:40.430 回答