Подтвердить что ты не робот

Разница между ArrayIterator, ArrayObject и Array в PHP

Может кто-нибудь ясно объяснить фундаментальные различия между ArrayIterator, ArrayObject и Array в PHP с точки зрения функциональности и работы? Спасибо!

4b9b3361

Ответ 1

Array - это родной тип php. Вы можете создать его, используя конструкцию языка php array() или с php 5.4 далее []

ArrayObject - это object, которые работают точно так же, как массивы. Они могут быть созданы с помощью new ключевого слова

ArrayIterator похож на ArrayObject, но он может итератировать сам по себе. Также создается с помощью 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 имеют определенные методы, которые вы можете использовать, в то время как для массивов не существует


Сравнение ArrayObject vs ArrayIterator

Основное различие между этими 2 заключается в методах, которые имеют классы.

ArrayIterator реализует интерфейс Iterator, который дает ему методы, связанные с итерацией/циклом над элементами. ArrayObject имеет метод под названием exchangeArray, который меняет его внутренний массив на другой. Реализация подобной вещи в ArrayIterator означала бы либо создание нового объекта, либо цикл через ключи, и unset все из них по одному, а затем поочередно установку элементов из нового массива.

Далее, поскольку ArrayObject не может быть повторен, когда вы используете его в foreach, он создает объект ArrayIterator внутренне (то же, что и массивы). Это означает, что php создает копию исходных данных, и теперь есть 2 объекта с одинаковым содержимым. Это окажется неэффективным для больших массивов. Тем не менее, вы можете указать, какой класс использовать для iterator, чтобы вы могли иметь пользовательские итераторы в своем коде.


Надеюсь, это полезно. Редактирование этого ответа приветствуется.

Ответ 2

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. Но нам нужно было сделать что-то, помнишь? Это пример класса, который не контролирует свой собственный внутренний статус.

Решение этого - итератор. Вместо передачи массива мы передаем массив новому объекту, который может только ПРОЧИТАТЬ вещи из массива. Самый простой Итератор - это примерно так:

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

Теперь снова есть только один способ добавить элементы в myArray в A, а именно через метод addSomethingToArray. Так вот что такое Итератор, это нечто вроде оболочки вокруг массивов, чтобы обеспечить что-то называемое инкапсуляцией.

Ответ 3

Возможно, вы найдете здесь свой ответ:

Этот итератор позволяет отменить и изменить значения и ключи во время итерации по массивам и объектам.

Если вы хотите перебирать один и тот же массив несколько раз, вам нужно для создания экземпляра ArrayObject и создания экземпляров ArrayIterator которые относятся к нему либо с помощью foreach, либо путем вызова его getIterator() вручную.

Также читайте:

Ответ 4

array - один из восьми примитивных типов в PHP. Несмотря на то, что он поставляется с множеством встроенных функций утилиты, но все они процедурные.

Оба ArrayObject и ArrayIterator позволяют нам создавать массивы граждан первого класса в объектно-ориентированной программе (ООП).

Разница между ArrayObject и ArrayIterator заключается в том, что, поскольку ArrayIterator реализует интерфейс SeekableIterator, вы можете сделать $myArray->seek(10); с помощью ArrayIterator.

Ответ 5

An Iterator - это объект, который позволяет программисту проходить контейнер, в частности списки. Различные типы итераторов часто предоставляются через интерфейс контейнера.

Нет большой разницы между ArrayObject и Array, поскольку они представляют одни и те же вещи, хотя и используют разные типы объектов.

ArrayIterator - это итератор, который выполняет итерации над объектами Array-like, включая все объекты, реализующие ArrayAcess и собственный Array тип. Фактически, когда вы foreach над массивом, PHP внутренне создает ArrayIterator для выполнения перемещения и преобразования вашего кода, чтобы выглядеть так, как будто это напечатано,

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

Итак, вы можете видеть, что каждый объект коллекции имеет Iterator, за исключением ваших определенных коллекций, которые вам нужно определить для ваших собственных итераторов.

Ответ 6

РЕДАКТИРОВАТЬ: забыл обратиться к нормальному массиву в моем ответе..

Прежде чем вы прочитаете все это, если вы новичок в 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 (см., Например, внизу).

Оба возвращают true для is_object(), оба возвращают false для is_array(), и оба позволяют прямой доступ к значениям в виде массива, не обеспечивая защиту для добавления значений и т.д., И оба могут передаваться по ссылке, позволяя манипулировать исходными данными во время цикл 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 который public getIterator ( void ): ArrayIterator обход значений внутри.

Вы всегда можете получить ArrayItterator From ArrayObject, если вам действительно нужны добавленные функции.

ArrayItterator - лучший выбор, если у вас есть собственный цикл псевдо-foreach для обхода странными способами и вы хотите лучше контролировать, а не просто начинать заканчивать обход.

ArrayItterator также был бы хорошим выбором для переопределения поведения массива по умолчанию, когда оно повторяется циклом foreach. например..

//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 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 - возможность более низкого уровня для управления или расширения и переопределения поведения обхода.

В.С.

ArrayObject - один контейнер для данных, но с возможностью изменения класса ArrayIterator.

Существуют и другие отличия, которые вы, возможно, захотите проверить, но я полагаю, что вы не поймете их полностью, пока не будете широко их использовать.

Похоже, что оба объекта могут использоваться по ссылке в foreach, но НЕ при использовании пользовательского класса itterator через 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 может использовать любые пользовательские ArrayIterator, которые вы создали на этом пути, id говорят, что это логический путь.

Надеюсь, это поможет вам так же, как помогло мне разобраться в этом.