Рефакторинг: замена массива объектом

Некоторые (особенно начинающие или неопытные) разработчики хранят в массивах разнородную информацию. Например:

$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);

Этот прием очень прост, но очень важен. Здесь я опустил этапы перевода - в лоб перевел структуру из «массивной» в объектную. Но в сложных проектах это делается не так быстро. На самом деле сначала надо было занести массив внутрь объекта, затем создать для каждого индекса массива отдельный метод, который изменяет/извлекает данные по этому индексу, потом создать для каждого индекса массива отдельное поле в классе и заменить все обращения по индексам в классе обращениями к соответствующим полям. И, в конце концов, удалить массив внутри класса, оставив только поля, заменяющие индексы существовавшего ранее массива.





Читайте также:



17 Ответов на “Рефакторинг: замена массива объектом”

  1. Юриус

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

  2. Sam

    Не лучше ли сначала рассказать, зачем оно надо без всяких предположений об отсутствии ассоциативного массива?

    Кстати:
    class Person extends ArrayObject {}

  3. novice

    2 Юриус: Да, верно. В PHP так делать не стоит. Но есть другие языки, где без этого обойтись сложно. Потом, не все разработчики комментируют код достаточно подробно. И интерпретация “первый элемент хранит имя человека” не всегда может вспомниться.

  4. novice

    2 Sam: “разработчику со временем становится сложно понимать, что скрывается под тем или иным индексом массива. И тут, конечно, мы должны применять объекты для хранения разнородной информации, ведь в массиве по хорошему должны храниться элементы одного типа”

  5. Sam

    «разработчику со временем становится сложно понимать, что скрывается под тем или иным индексом массива»

    Чем же $person->setName(‘Vasily’) лучше, чем $person[‘name’] = ‘Vasily’?

    «в массиве по хорошему должны храниться элементы одного типа»
    По какому такому «хорошему»? Массив в PHP — это хэш, а не, например, типизированный List в Java.

    Не стоит пренебрегать возможностями языка и городить непонятно что…

    На самом деле описанный вами пример — штука полезная, но, во-первых, немного не в таком виде, а во-вторых — совсем не для того, для чего вы описали.

  6. novice

    Заметьте, что цикл статей про рефакторинг не подразумевает обязательное его использование в PHP. Замена массива объектом - лишь небольшой прием, который целесообразен не для всех языков программирования (например, он не нужен для PHP). Поэтому я и привел пример на PHP, но при этом сказал, что если бы не было ассоциативных, то пришлось бы поступать так и так. И я нисколько не призываю пренебрегать возможностями языка. Данный блог посвящен вопросам программирования на PHP, поэтому я не стал приводить здесь примеры для других языков. В общем, суть этого поста - показать смысл описываемого приема рефакторинга.

  7. Sam

    Ну так зачем пример давать на PHP, если он к нему не подходит? Смысла не видно как раз из-за того, что пример на PHP.

  8. cryptus

    Sam так много написал - я чуть было не подумал, что ты знаешь о чем говоришь 😉 Шучу. На самом деле разница между ассоциативным массивом и объектом в данном случае принципиальная. Первый используется при процедурном программировании, второй при ООП. Так что не надо больше демагогии тут разводить, пожалуйста.

  9. Sam

    Ассоциативный массив не используется в ООП?

    На самом деле отличия в статье просто не показаны:
    1. Инкапсуляция полей, которые в примере тут у нас почему-то public(var), а не private/protected.
    2. Не показано, что даёт такая обёртка. Можно было-бы, например, валидировать поля в set-методах.

    Да и чем лучше объект массива в данном случае? Ничем.

  10. cryptus

    Ну, а в чем преимущество ООП перед процедурным программированием? Цель статьи, как я понял - продемонстрировать технику, а не обосновать ее существование.
    > “Да и чем лучше объект массива в данном случае? Ничем.”
    Если у тебя есть проект в процедурном стиле и ты хочешь его перевести на ООП, то тебе этот прием понадобиться и из статьи ты узнаешь как это сделать. При чем тут лучше или не лучше? :)

  11. novice

    “Инкапсуляция полей, которые в примере тут у нас почему-то public(var), а не private/protected.”

    Это справедливо только для версии PHP5, а данный пост я старался написать, охватив и 4-ю.

  12. Sam

    ООП нужен там, где он действительно нужен. Заменять ассоциативный массив на объект, «переводить на ООП», не добавляя ничего полезного и нужного по крайней мере глупо. Да, кстати, ещё и ощутимо медленнее.

    «Цель статьи, как я понял - продемонстрировать технику, а не обосновать ее существование.»
    Тогда надо в названии блога убрать слово «новичка» т.к. новички часто начинают делать, не усомнившись в необходимости данной техники.

    В таком виде в PHP она не нужна как в PHP4, так и в PHP5. Зачем была демонстрация?

  13. novice

    Хех :) В каждом посте всегда есть недостатки.

  14. Sam

    Ну так исправляться надо 😉

  15. Если есть необходимость в автовалидации вносимых в массив данных, то можно обернуть в класс и задействовать такую полезную фишку как геттеры и сеттеры. В классе будет всего 1 свойство - наш массив. В нём же прописываем приватный метод-валидатор.

    Вносить данные будем так:
    $data->somekey1 = ‘key1′; //Создали в свойстве-массиве элемент с ключём somekey1 и занесли в него значение key1 после валидации.

    Чтение ещё проще:
    echo $data->somekey1;

    Ну а если нет необходимости в валидации, то, естественно, удобнее использовать простые массивы (если говорить о PHP).Не засоряется память и работает чуть побыстрее объектов.

  16. Сергей

    Господа! Явное преимущество данного подхода заключается в том, что мы видим всю структуру данных, т.е. какие поля есть, а каких быть не должно. Что попало мы в объект не добавим, в отличие от массива.

  17. толян

    хорошая статья. Не хрен на аффтара бочки катить-он пацан правильный.


© Copyright. . I-Novice. All Rights Reserved. Terms | Site Map