PHP - это язык смешанной парадигмы, позволяющий использовать и возвращать необъектные типы данных, такие как массивы. Я задаю вопрос, чтобы попытаться прояснить некоторые рекомендации по выбору массивов и объектов при принятии решения о том, какую программную конструкцию использовать в конкретной ситуации.
Это действительно вопрос о способах кодирования данных с использованием языковых конструкций PHP и о том, когда один путь должен быть более вероятен, чем другой для целей передачи данных (т. Е. Сервис-ориентированная архитектура или веб-сервисы).
пример
Предположим, у вас есть тип элемента, состоящий из {cost, name, part_number, item_count}. Ваша программа требует отображения нескольких таких типов элементов, чтобы вы решили использовать массив в качестве внешнего контейнера для хранения каждого из типов элементов. [Вы также можете использовать PHP ArrayObject
для ОО-парадигмы, но мой вопрос не об этом (внешнем) массиве]. Мой вопрос о том, как кодировать данные типа элемента и какую парадигму использовать. PHP позволяет использовать PHP Native Arrays
или PHP Objects
.
Я могу закодировать такие данные двумя способами, вот так:
//PHP's associative arrays:
$ret = array(
0 => array(
'cost' => 10.00,
'name' => 'item1',
'part_number' => 'zyz-100',
'item_count' => 15
),
1 => array(
'cost' => 34.00,
'name' => 'item2',
'part_number' => 'abc-230',
'item_count' => 42
),
);
против
//here ItemType is encapsulated into an object
$ret = array(
0 => new ItemType(10.00, 'item1', 'zyz-100', 15),
1 => new ItemType(34.00, 'item2', 'abc-230', 42),
);
class ItemType
{
private $price;
private $name;
private $partNumber;
private $itemCount;
function __construct($price, $name, $partNumber, $itemCount) {..}
}
О чем я думаю
Кодирование массива облегчено и более готово к JSON, но может быть проще испортить. Неправильно написан один из ключей ассоциативного массива, и может возникнуть ошибка, которую сложнее отследить. Но это также легче изменить по прихоти. Скажем, я не хочу item_count
больше хранить , я могу использовать любое программное обеспечение для обработки текста, чтобы легко удалить все item_count
экземпляры в массиве и затем обновить другие функции, которые используют его соответствующим образом. Это может быть более утомительный процесс, но это просто.
Объектно-ориентированное кодирование требует использования языковых возможностей IDE и PHP и облегчает обнаружение любых ошибок заранее, но в первую очередь сложнее для программирования и кодирования. Я говорю сложнее, потому что вы должны немного подумать о своих объектах, подумать заранее, и ОО-кодирование требует немного большей когнитивной нагрузки, чем типизация структур массива. Тем не менее, после его кодирования некоторые изменения могут быть легче реализованы, в том смысле, что удаление item_count
, например, потребует изменения меньшего количества строк кода. Но сами изменения могут по-прежнему требовать более высокой когнитивной нагрузки по сравнению с методом массива, так как задействованы средства OO более высокого уровня.
Вопрос
В некоторых случаях это понятно, например, в случаях, когда мне нужно будет выполнять манипуляции с данными. Но в некоторых случаях, когда мне нужно просто сохранить несколько строк данных «Тип элемента», у меня нет четких рекомендаций или соображений, на которые следует опираться при попытке решить, использовать ли массивы или создавать объекты. Кажется, я могу просто бросить монетку и выбрать одну. Это тот случай здесь?
(object)['foo'=>'bar']
. Полученное значение имеет классStdClass
, будет полностью закодировано в JSON-коде,json_encode()
и свойства можно будет переименовывать так же легко, как индексы массива (что не всегда так просто, когда к нему обращаются косвенно через переменную). Однако существуют разные операции с такими значениями; например, у вас нет объединений объектов, так как у вас есть объединения массивов, и вы не можете напрямую использоватьarray_*()
функции.array
, 2:User-defined Class
, 3:stdClass
. Производительность с точки зрения скорости почти одинакова при сравненииarray
и aUser-defined class
(например, вашегоItemType
), но определенныеclass
es, как правило, используют меньше памяти, чемarray
s.stdClass
с другой стороны, это самый медленный из трех вариантов, который также использует больше всего памяти.Ответы:
То, как я это вижу, зависит от того, что вы собираетесь делать с данными впоследствии. Основываясь на нескольких простых проверках, вы можете определить, какая из двух структур данных вам подходит:
Есть ли у этих данных какая-либо логика, связанная с этим?
Например,
$price
хранится как целое число центов, так что продукт с ценой в $ 9,99 будет иметь,price = 999
а неprice = 9.99
? (Возможно, да) ИлиpartNumber
нужно соответствовать определенному регулярному выражению? Или вам нужно легко проверитьitemCount
наличие в вашем инвентаре? Вам нужно будет выполнить эти функции в будущем? Если это так, то лучше всего создать класс сейчас. Это означает, что вы можете определить ограничения и логику, встроенные в структуру данных:private $myPrice
установлено в значение,999
но$item->getPriceString()
возвращается$9.99
и$item->inStock()
доступно для вызова в вашем приложении.Вы собираетесь передавать эти данные нескольким функциям PHP?
Если так, то используйте класс. Если вы генерируете эти данные один раз для выполнения каких-либо преобразований или просто для отправки данных в формате JSON в другое приложение (JavaScript или другое), тогда массив будет более легким выбором. Но если у вас есть более двух функций PHP, которые принимают эти данные в качестве параметра, используйте класс. Если ничего другого, это позволяет вам определить,
someFunction(MyProductClass $product) {
и очень ясно, что ваши функции ожидают в качестве ввода. По мере того, как вы масштабируете свой код и получаете больше функций, будет намного легче узнать, какой тип данных принимает каждая функция. ВидетьsomeFunction($someArrayData) {
не так ясно. Кроме того, это не обеспечивает согласованность типов и означает, что (как вы сказали) гибкая структура массива может позже вызвать боль при разработкеВы строите библиотеку или базу общего кода?
Если это так, используйте класс! Подумайте о каком-то новом разработчике, который использует вашу библиотеку, или о другом разработчике в компании, который никогда раньше не использовал ваш код. Им будет гораздо проще взглянуть на определение класса и понять, что делает этот класс, или увидеть ряд функций в вашей библиотеке, которые принимают объекты определенного класса, чем пытаться угадать, какую структуру им нужно создать в количество массивов. Кроме того, это касается проблем согласованности данных с № 1: если вы разрабатываете библиотеку или базу общего кода, будьте добры к своим пользователям: предоставьте им классы, которые обеспечивают согласованность данных и защитят их от ошибок при проектировании ваших данных ,
Это небольшая часть приложения или просто преобразование данных? Вы не вписываетесь ни в один из вышеперечисленных?
Класс может быть слишком много; используйте массив, если он вам подходит, и вам будет проще. Как упоминалось выше, если вы просто генерируете структурированные данные для отправки в формате JSON, YAML, XML или чего-либо другого, не беспокойтесь о классе, если в этом нет необходимости. Если вы пишете небольшой модуль в более крупном приложении, и никакие другие модули / группы не должны взаимодействовать с вашим кодом, возможно, достаточно массива.
В конечном счете, рассмотрите потребности вашего кода в масштабировании и подумайте, что структурированный массив может быть быстрым решением, но класс является гораздо более гибким и масштабируемым решением.
Также учтите следующее: если у вас есть класс, и вы хотите вывести его в JSON, нет причины, по которой вы не можете определить
json_data()
метод вашего класса, который возвращает JSON-ifiable массив данных в классе. Это то, что я делал в своих приложениях PHP, где мне нужно было отправлять данные классов в формате JSON. В качестве примера:источник
my_lineitems
, поэтому получать их по ссылке не нужно, тем более что переменные содержат только идентификатор объекта, а не сам объект. php.net/manual/en/language.oop5.references.phpВы можете реализовать структуру json с помощью интерфейса JsonSerializable и использовать вложенный массив / класс любым способом. Класс быстрее в операциях get / set и легче в отладке. С Array вам не нужно декларировать.
источник
json_encode(['order'=>$o]);
в existsing общепринятого ответ пустой:{"order":{}}
. Конечно, вы можете использовать:$o->forJSON()
каждый раз на каждом объекте на каждом уровне, но это не очень хороший дизайн. Потому что все время нужно писать что-то вроде:$items_json = array(); foreach($this->my_lineitems as $item) $items_json[] = $item->forJSON();