Как стать автором
Обновить

PHP и ООП. Совмещаем \«несовмещаемое\»…

PHP *
Объектно-ориентированное программирование — как стиль жизни. Это не просто применение конструкций типа class или interface — это способ мышления, когда любая сущность программы является не просто набором инструкций, а представляет из себя \«живое\» существо…

Думаю напоминать что такое ООП, в рамках данной статьи, будет лишним, посему перейду сразу к проблематике вопроса.

Разработчики, пришедшие в PHP из других языков программирования, и столкнувшиеся в нем (в РНР. тут и далее буду подразумевать РНР5 — прим.) с классами, недоумевают как их вообще возможно использовать. А все из-за того, что время жизни скрипта на РНР гораздо меньше, чем у прикладного ПО и составляет всего один цикл работы, в то время как прикладное ПО может жить и взаимодействовать со своими компонентами много дольше. В итоге миру является код, в котором классы реализуют всего-навсего отсутствующие в РНР namespaces.

class A {
    public static function b() {}

    public static function c() {}

    public static function d() {}
}

Да — даже у такого подхода есть масса плюсов. Например мы смогли выделить функции относящиеся к одной области данных в класс-обертку, что уменьшило вероятность конфликта имен функций в коде, а так же читабельность кода и отслеживание поведений функций становится более прозрачным:

User::register($name, $pwd);
//... a lot of code ...
System::Log($message, $code);

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

Но давайте взглянем на ООП не просто как парадигму программирования с уже приевшимся основными чертами: наследование, инкапсуляция и полиморфизм, а посмотрим на него как на мир, окружающий нас. О чем нам говорят предметы, что вокруг? Возьмем к примеру мои очки. Что можно о них сказать? Можно измерить их вес и размер, цвет и плотность — это будут свойства класса \«очки\», но к этому они еще могут разбиться и преломлять проходящий через линзы свет — а это уже методы. Пить чай из очков у нас не получиться, точно так же как и измерить скорость очков. О чем это говорит? Класс \«очки\» имеет определенную сферу применения и возможности по взаимодействию. Точно так же мы можем поступать с нашими классами в РНР.

Хоть цикл жизни скрипта всего один, но его можно прожить красиво! Этим и попытаемся заняться…
Представим что у нас есть социальная сеть (ну а как же нынче без них? :)); в этой соц.сети есть пользователи, а каждый пользователь имеет свой блог. А теперь попытаемся лаконично и элегантно отобразить сферы действия каждой из представленных сущностей.
Пользователь имеет набор свойств. Пусть это будут: логин, пароль и email. Пользователь может совершать некоторые действия: логиниться, выходить, создавать блог и писать в него.
Блог в свою очередь имеет свойствами: автора, коллекцию топиков и дату создания. Блог может добавлять в себя запись.
Ограничимся этим набором методов и свойств сущностей. Как элегантнее всего представить подобную структуру в коде? Предлагаю следующий вариант:
class Blog {
    public $topics_list;
    public $creation_date;
    private $data; //свойства объекта, взятые из БД

    public function __construct($id) { //id блога
        //где-то тут заполняем $this->data, к примеру из БД
    }

    public function getAuthor() {
        static $author; //объявим пользователя статическим, что бы не расходовать ресурсы в случае, если получать пользователя нам не прийдется, а так же оградимся от неправильного доступа к этому псевдо-свойству класса

        if (empty($author)) {
            $author = new User($this->data[\'author_id\']);
    }

        return $author;
    }

    public function addTopic(Topic $topic) { ... } //метод описывать не буду. Главное понимать что он делает
}

class User { ... } //описывать пользователя не буду, что бы не нагромождать код, но смысл его методов будет подобный


Итак — чего мы добились? Создав оба класса подобным образом в итоге мы имеем четкие области ответственности каждого объекта, к тому же мы не будем заворачиваться с передачей ненужных параметров. К примеру создадим запись в блоге \«по-старинке\» и исходя из описанных макетов.
По-старинке:
$user_id = $_SESSION[\'user_id\']; //предполагаем идентификацию пользователя по его id из сессии

$topic_message = \"Новый топик\";
Blog::addTopic($user_id, $topic_message); //укажем для какого пользователя добавляется запись

Все вроде бы понятно и естественно, кроме одного — при передачи аргументов для создания топика, становится не очевидным роль пользователя. Посмотрим как будет выглядеть этот же код с новым подходом:
$user = new User($_SESSION[\'user_id\']);
$topic_message = \"Новый топик\";

$user->getBlog()->addTopic($topic_message);

Тут гараздо очевиднее взаимоотношения между блогом и пользователем… А если подумать что топик — тоже объект и у него есть свойство \«сообщение\», то получить его мы моглибы так:
$user = new User($_SESSION[\'user_id\']);
echo $user->getBlog()->getTopics()->topic[$topic_id]->message;


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

Если после прочтения появились вопросы, буду рад на них ответить.

P.S. Подскажите как оформлять участки кода в топиках на Хабре, а то как-то не читабельно у меня получилось :(
Теги:
Хабы:
Всего голосов 22: ↑16 и ↓6 +10
Просмотры 3.7K
Комментарии Комментарии 62