Рефакторинг: замена массива объектом
Некоторые (особенно начинающие или неопытные) разработчики хранят в массивах разнородную информацию. Например:
$arr = Array(); $arr[0] = “Mike”; // имя человека $arr[1] = 30; // возраст $arr[2] = 180; // рост
Хорошо, что в PHP есть ассоциативные массивы, которые позволили бы нам написать вот так:
$arr = Array(); $arr[‘name’] = “Mike”; $arr[‘age’] = 30; $arr[‘stature’] = 180;
Но представим, что у нас ассоциативных массивов нет (а их на самом деле нет в некоторых языках программирования). Тогда разработчику со временем становится сложно понимать, что скрывается под тем или иным индексом массива. И тут, конечно, мы должны применять объекты для хранения разнородной информации, ведь в массиве по хорошему должны храниться элементы одного типа.
Попробуем превратить наш массив в объект:
class Person { var $name; var $age; var $stature; function SetName($name) { $this->name = $name; } function GetName() { return $this->name; } function SetAge($age) { $this->age = $age; } function GetAge($age) { return $this->age; } function SetStature($stature) { $this->stature = $stature; } function GetStature() { return $this->stature; } }
Теперь мы можем переделать приведенный ранее кусок кода в следующий:
$person = new Person(); $person->SetName(“Mike”); $person->SetAge(30); $person->SetStature(180);
Этот прием очень прост, но очень важен. Здесь я опустил этапы перевода - в лоб перевел структуру из «массивной» в объектную. Но в сложных проектах это делается не так быстро. На самом деле сначала надо было занести массив внутрь объекта, затем создать для каждого индекса массива отдельный метод, который изменяет/извлекает данные по этому индексу, потом создать для каждого индекса массива отдельное поле в классе и заменить все обращения по индексам в классе обращениями к соответствующим полям. И, в конце концов, удалить массив внутри класса, оставив только поля, заменяющие индексы существовавшего ранее массива.
Я использую ассоциативные массивы для сбора данных в шаблонизатор. Хоть убейте, не понимаю, зачем городить огород с объектами, если по сути получается то же самое. Да и комментарии же никто не отменял
Не лучше ли сначала рассказать, зачем оно надо без всяких предположений об отсутствии ассоциативного массива?
Кстати:
class Person extends ArrayObject {}
2 Юриус: Да, верно. В PHP так делать не стоит. Но есть другие языки, где без этого обойтись сложно. Потом, не все разработчики комментируют код достаточно подробно. И интерпретация “первый элемент хранит имя человека” не всегда может вспомниться.
2 Sam: “разработчику со временем становится сложно понимать, что скрывается под тем или иным индексом массива. И тут, конечно, мы должны применять объекты для хранения разнородной информации, ведь в массиве по хорошему должны храниться элементы одного типа”
«разработчику со временем становится сложно понимать, что скрывается под тем или иным индексом массива»
Чем же $person->setName(‘Vasily’) лучше, чем $person[‘name’] = ‘Vasily’?
«в массиве по хорошему должны храниться элементы одного типа»
По какому такому «хорошему»? Массив в PHP — это хэш, а не, например, типизированный List в Java.
Не стоит пренебрегать возможностями языка и городить непонятно что…
На самом деле описанный вами пример — штука полезная, но, во-первых, немного не в таком виде, а во-вторых — совсем не для того, для чего вы описали.
Заметьте, что цикл статей про рефакторинг не подразумевает обязательное его использование в PHP. Замена массива объектом - лишь небольшой прием, который целесообразен не для всех языков программирования (например, он не нужен для PHP). Поэтому я и привел пример на PHP, но при этом сказал, что если бы не было ассоциативных, то пришлось бы поступать так и так. И я нисколько не призываю пренебрегать возможностями языка. Данный блог посвящен вопросам программирования на PHP, поэтому я не стал приводить здесь примеры для других языков. В общем, суть этого поста - показать смысл описываемого приема рефакторинга.
Ну так зачем пример давать на PHP, если он к нему не подходит? Смысла не видно как раз из-за того, что пример на PHP.
Sam так много написал - я чуть было не подумал, что ты знаешь о чем говоришь 😉 Шучу. На самом деле разница между ассоциативным массивом и объектом в данном случае принципиальная. Первый используется при процедурном программировании, второй при ООП. Так что не надо больше демагогии тут разводить, пожалуйста.
Ассоциативный массив не используется в ООП?
На самом деле отличия в статье просто не показаны:
1. Инкапсуляция полей, которые в примере тут у нас почему-то public(var), а не private/protected.
2. Не показано, что даёт такая обёртка. Можно было-бы, например, валидировать поля в set-методах.
Да и чем лучше объект массива в данном случае? Ничем.
Ну, а в чем преимущество ООП перед процедурным программированием? Цель статьи, как я понял - продемонстрировать технику, а не обосновать ее существование.
> “Да и чем лучше объект массива в данном случае? Ничем.”
Если у тебя есть проект в процедурном стиле и ты хочешь его перевести на ООП, то тебе этот прием понадобиться и из статьи ты узнаешь как это сделать. При чем тут лучше или не лучше?
“Инкапсуляция полей, которые в примере тут у нас почему-то public(var), а не private/protected.”
Это справедливо только для версии PHP5, а данный пост я старался написать, охватив и 4-ю.
ООП нужен там, где он действительно нужен. Заменять ассоциативный массив на объект, «переводить на ООП», не добавляя ничего полезного и нужного по крайней мере глупо. Да, кстати, ещё и ощутимо медленнее.
«Цель статьи, как я понял - продемонстрировать технику, а не обосновать ее существование.»
Тогда надо в названии блога убрать слово «новичка» т.к. новички часто начинают делать, не усомнившись в необходимости данной техники.
В таком виде в PHP она не нужна как в PHP4, так и в PHP5. Зачем была демонстрация?
Хех В каждом посте всегда есть недостатки.
Ну так исправляться надо 😉
Если есть необходимость в автовалидации вносимых в массив данных, то можно обернуть в класс и задействовать такую полезную фишку как геттеры и сеттеры. В классе будет всего 1 свойство - наш массив. В нём же прописываем приватный метод-валидатор.
Вносить данные будем так:
$data->somekey1 = ‘key1′; //Создали в свойстве-массиве элемент с ключём somekey1 и занесли в него значение key1 после валидации.
Чтение ещё проще:
echo $data->somekey1;
Ну а если нет необходимости в валидации, то, естественно, удобнее использовать простые массивы (если говорить о PHP).Не засоряется память и работает чуть побыстрее объектов.
Господа! Явное преимущество данного подхода заключается в том, что мы видим всю структуру данных, т.е. какие поля есть, а каких быть не должно. Что попало мы в объект не добавим, в отличие от массива.
хорошая статья. Не хрен на аффтара бочки катить-он пацан правильный.