PHP中ArrayIterator,ArrayObject和Array之间的区别

时间:2012-05-08 16:37:53

标签: php arrays arrayobject arrayiterator

有人可以在功能和操作方面清楚地解释PHP中ArrayIteratorArrayObject和Array之间的根本区别吗?谢谢!

6 个答案:

答案 0 :(得分:24)

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

ArrayObjectobject,其工作方式与数组完全相同。可以使用new关键字

创建这些内容

ArrayIteratorArrayObject类似,但它可以自行迭代。也是使用new

创建的

比较Array vs(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个具有相同内容的对象。对于大型阵列来说,这将被证明是低效的。但是,您可以指定要用于迭代器的类,因此您可以在代码中使用自定义迭代器。


希望这有帮助。欢迎编辑这个答案。

答案 1 :(得分:9)

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

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

你有一个有数组的类。您可以使用addSomethingToMyArray将项添加到该数组。但是请注意,在我们将它实际添加到数组之前,我们会对项目执行某些操作。这可能是任何事情,但是让我们暂时表示,对于我们想要添加到数组的每个项目来说,触发此方法非常重要。

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。但是我们需要做SOmethingToItem,还记得吗?这是一个不控制自己内在状态的类的例子。

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

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

&GT;

正如您所看到的,我无法向给定数组添加新项目,但我确实有可能像这样读取数组:

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

现在又有一种方法可以通过addSomethingToArray方法向A中的myArray添加项目。所以这就是Iterator,它有点像数组的shell,提供一些叫做封装的东西。

答案 2 :(得分:0)

您可以在这里找到答案:

  

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

     

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

同时阅读:

答案 3 :(得分:0)

array是PHP中的八种原始类型之一。虽然它附带了许多内置的实用功能,但它们都是程序性的。

ArrayObjectArrayIterator都允许我们在面向对象程序(OOP)中创建数组的第一类公民。

ArrayObjectArrayIterator之间的区别在于,由于ArrayIterator实现了SeekableIterator界面,您可以使用$myArray->seek(10);执行ArrayIterator。< / p>

答案 4 :(得分:0)

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

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

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

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

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

答案 5 :(得分: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,以获取有关该概念的出色示例(低级类文档)。

Intellisense suggestions of the arrow functions

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

Intellisense of array 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使用自定义的itterator类时则不能使用。

//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可以利用您在此过程中创建的任何自定义ArrayIterator,id表示这是要采用的逻辑路径。

希望这对您有帮助,对我帮助很大。

相关问题