Класс Collection является заменой ООП для традиционной структуры данных массива. Как и массив, коллекция содержит элементы-члены, хотя обычно это объекты, а не простые типы, такие как строки и целые числа.
Общие характеристики класса коллекции:
- Устанавливает обертку вокруг массива объектов.
- Коллекции являются изменяемыми — новые элементы могут быть добавлены, а существующие элементы могут быть изменены или удалены.
- Алгоритмы сортировки нестабильны (что означает, что порядок для равных элементов не определен).
- Можно использовать ленивый экземпляр для экономии системных ресурсов.
Проблема с массивами
Приложения часто имеют объекты, которые содержат группу других объектов, и это отличное место для использования коллекций. Например, предположим, что мы решили создать систему книжного магазина. Допустим, мы написали класс клиента, который, помимо прочего, содержит список книг, которые клиент хотел бы приобрести:
<?php class Customer { public $items = array(); // ... } $customer = new Customer(1234); foreach ($customer->items as $item) { echo $item->name; }
Если бы наиболее очевидный подход (использование массива) был наилучшим из возможных, я бы не стал писать эту статью. Приведенный выше пример имеет следующие проблемы:
- Мы нарушили инкапсуляцию — массив представлен как переменная-член public.
- Существует неопределенность в индексации и в том, как пройти через массив, чтобы найти конкретный элемент.
Кроме того, чтобы убедиться, что массив доступен для любого кода, который может получить к нему доступ, мы должны заполнить список информации из базы данных одновременно с информацией о клиенте. Это означает, что даже если мы хотим напечатать только имя клиента, мы должны получить всю информацию об элементе, что излишне увеличивает нагрузку на базу данных и может привести к зависанию всего приложения.
Мы можем решить эти проблемы, создав класс коллекции в качестве оболочки ООП вокруг массива и используя ленивую реализацию. Ленивый экземпляр — это механизм, с помощью которого мы создаем элементы в массиве только тогда, когда он нам действительно нужен. Это называется «ленивый», потому что объект сам определяет, когда создавать экземпляры объектов-компонентов, а не слепо создавать их при создании.
Базовый Класс Коллекции
Класс коллекции должен предоставлять методы, которые позволяют нам добавлять, извлекать и удалять элементы, и полезно иметь метод, который позволяет нам знать размер коллекции. Итак, базовый класс начнется так:
<?php class Collection { private $items = array(); public function addItem($obj, $key = null) { } public function deleteItem($key) { } public function getItem($key) { } }
Массив $items
предоставляет место для хранения объектов, которые являются членами коллекции. addItem()
позволяет нам добавить новый объект в коллекцию, deleteItem()
удаляет объект, а getItem()
возвращает объект.
С помощью addItem()
мы добавляем объект в коллекцию, помещая его в массив $items
в указанном месте, указанном в $key
(если ключ не указан, мы разрешаем PHP выбирать следующий доступный индекс). Если предпринята попытка добавить объект с использованием уже существующего ключа, следует сгенерировать исключение, чтобы предотвратить непреднамеренную перезапись существующей информации:
public function addItem($obj, $key = null) { if ($key == null) { $this->items[] = $obj; } else { if (isset($this->items[$key])) { throw new KeyHasUseException("Key $key already in use."); } else { $this->items[$key] = $obj; } } }
deleteItem()
и getItem()
принимают ключ в качестве параметра, указывающего, какие элементы предназначены для удаления или извлечения. Исключение следует выдавать, если указан неверный ключ.
public function deleteItem($key) { if (isset($this->items[$key])) { unset($this- >items[$key]); } else { throw new KeyInvalidException("Invalid key $key."); } } public function getItem($key) { if (isset($this->items[$key])) { return $this->items[$key]; } else { throw new KeyInvalidException("Invalid key $key."); } }
Поскольку параметр $ key для addItem()
является необязательным, мы не обязательно будем знать ключ, используемый для каждого элемента в коллекции. Хорошая идея — добавить метод, который может предоставить список ключей для любого внешнего кода, который может понадобиться. Ключи могут быть возвращены в виде массива:
public function keys() { return array_keys($this->items); }
Также может быть полезно узнать, сколько предметов в коллекции.
public function length() { return count($this->items); }
А поскольку getItem()
и deleteItem()
могут deleteItem()
исключение, если передан недопустимый ключ, хорошей идеей также является определение того, существует ли данный ключ в коллекции.
public function keyExists($key) { return isset($this->items[$key]); }
Чтобы использовать класс Collection
в его нынешнем виде, создайте файл Collection.php
и сохраните в нем код для класса Collection
. Также создайте файлы для классов KeyInvalidException
и KeyhasUseException
(они могут быть простыми подклассами базового класса Exception
). Обязательно добавьте операторы require, если вы не используете автозагрузчик, а затем попробуйте следующий тестовый код:
<?php require_once "Collection.php"; class Salut { private $name; private $number; public function __construct($name, $number) { $this->name = $name; $this->number = $number; } public function __toString() { return $this->name . " is number " . $this->number; } } $c = new Collection(); $c->addItem(new Salut("Steve", 14), "steve"); $c->addItem(new Salut("Ed", 37), "ed"); $c->addItem(new Salut("Bob", 49), "bob"); $c->deleteItem("steve"); try { $c->getItem("steve"); } catch (KeyInvalidException $e) { print "The collection doesn't contain Steve."; }
Этот пример может быть не особенно интересным, но он должен дать вам представление о том, как используется класс.
Вывод
Коллекции можно рассматривать как более специализированный способ работы со списками, для которых определенные контракты гарантированы. Класс Collection — это очень полезная альтернатива ОО традиционному массиву, который можно реализовать практически в любом приложении, которое вы можете создать. Он обеспечивает тщательное управление своими членами и непротиворечивый API, который облегчает написание кода, использующего класс.