Дисклэймер: мне нужно было объяснить моему сотруднику зачем нужны классы в принципе, а именно в чём их преимущество перед функциями. Я начал фантазировать примеры кода, и написал много комментариев. В итоге я посмотрел на то что получилось и подумал - а не дерзнуть ли в песочницу на Хабре?
Что такое хороший код?
Это востребованный код, то есть код который работает в живом проекте
Это не сильно связанно с темой, но это нужно понимать, так как остальное следует из первого пунктаЭто код, который работает с минимальным количеством ошибок
Это код, который удобно поддерживать и расширять (не важно, будет ли это делать один человек или команда разработчиков)
Классы помогают писать хороший код
Буду рассматривать классы не как необходимый инструмент парадигмы ООП, а как инструмент проектирования системы (и стараться доказать их преимущества перед функциями)
Читаемость
<?php $Article = new Article($articleId); $Article->setMeta('');
Банально читается понятнее чем
<?php article_set_meta($articleId, '');
Даже без подсветки синтаксиса IDE. А с подсветкой - кратно понятнее.
Да, это одна лишняя строчка кода, но если речь о количестве символов - в масштабах проекта это экономия.
Пример более очевиден с увеличением масштаба
<?php $Article = new Article($articleId); $Article->setMeta('')->addImage('')->markAsHot(); $Article->render();
VS
<?php article_set_meta($articleId, ''); article_add_image($articleId, ''); article_mark_as_hot($articleId); article_render($articleId);
Организация кода
Структура с нэймспэйсами и классами визуально понятнее
<?php /Article/Article::create(); /Article/Gallery/Gallery::create(); /* VS */ article_create(); article_gallery_create();
При соблюдении хоть каких-то стандартов код с классами сразу рисует в голове структуру проекта, просто мозг так работает.
Да, любая IDE по клику на метод или функцию найдёт её, но в случае с функциями мозгу не очевидна структура, особенно в большом проекте где 10-ки классов и методов (или сотни функций)
В командной разработке очень удобно отдавать разные Классы/Нэймспэйсы, можно сказать, модули, разным исполнителям.
Ассоциация с реальными вещами в жизни
Когда мы мыслим в рамках классов - нам проще строить сложные структуры, потому что мозг ассоциирует классы и методы с реальными (или абстрактными) понятиями
<?php $User = new User(); //Посетитель, человек $Article = new Article($id); // Статья на сайте, читаемый на мониторе текст $Article->readBy($User); // Статья прочитана человеком $user = get_from_session(); // Что-то про сессии $article = get_article_by_id($id); // Что-то get и id article_read_by_user($article, $user); // Вроде понятно, но не с первого прочтения
Инкапсуляция, как инструмент скрывания внутреннего функционала
Private и Protected методы нужны не для абстрактных доктрин ООП.
Самое банальное - при подстановке кода IDE не будет показывать Private и Protected методы
Опять же, про работу мозга - такие методы помогают переключаться с объекта и его внутренних методов на более высокие уровни структуры, когда мы работаем с конкретным объектом - мы можем быстро сфокусироваться на нём, когда на высоком уровне - "забыть" какие-то внутренние методы объекта. С функциями такое просто не получится, потому что они все видны, мозгу сложно держать в памяти их все, также как сложно вспоминать конкретные наборы функций, потому что он перебирает все.
А самое главное - без таких методов не получится хорошо спроектировать систему, немного об этом ниже
Шаблоны проектирования
Шаблоны проектирования - набор отточенных годами практик, которые помогают решать сложные задачи, причём таким образом, чтобы было понятно всем (кто знаком с реализованным шаблоном). Без классов(и ООП) они просто не получатся. Конечно, можно сделать их на функциях... Хотя нет, нельзя.
И, немного о архитектуре
Хороший проект - это не просто код, это код, связанный архитектурой. Архитектура задаёт стандарты, помогает разным программистам работать над разными частями, повышает отказоустойчивость системы. Во многом это делается благодаря уровням.
Самый высокий уровень
<?php $Client = new Client($clientId); $Product = new Product($productId); $Invoice = InvoiceBuilder::create($Client); $Invoice->addProduct($Product, $amount, $sellPrice); $Invoice->checkout();
На этом уровне мы не обязаны знать что там под капотом. Мы пишем понятную человеческими словами логику. Нам очевидно что мы выписали счёт клиенту. По этому и классы: чисто визуальнее они понятнее чем функции, вот есть счёт, мы что-то в него добавили, и выписали его.
Средний уровень
<?php class Invoice { public function addProduct(Product $Product, int $amount, int $sellPrice) { // Добавим товар в счёт $this->products[] = [ 'product' => $Product->id, 'amount' => $amount, 'sellPrice' => $sellPrice, ]; // Запомним выбор клиента, если он не оформит покупку - будем ему спамить этот товар $EvilTracker = new EvilTracker($this->Client); $EvilTracker->track($Product->id); // Создадим запись для отдела аналитики по добавленному товару ProductAnalytics::log($Product->id, $amount, $sellPrice, 'added-to-basket'); } }
Смысл его в том что на этом уровне мы можем менять поведение системы, не затрагивая верхний уровень, добавить какие-то действия, убрать, и тд. Здесь классы нужны чтобы
Реализовывать инкапсуляцию, делать код "модульным" и прятать методы-функции от других классов-модулей синтаксис классов и нэймспэйсов для этого просто удобен.
Реализовывать наследование, это очень хорошая штука для разработки и проектирования.
Реализовывать шаблоны проектирования.
При хорошей архитектуре мы меняем EvilTracker() на SpareTracker() и всё работает.
Низкий уровень
<?php class { public function someLowLevelLogic(bool $boolSomething):array { $someArray = mysql::get_something(); if ($boolSomething) { $someArray = array_map(function ($element) { return [ 'id' => $element['id'], 'title' => $element['title'] . ' ' . $element['bankTitle'], ]; }, $someArray); } returm $someArray; } }
Разделение на уровни и модули (под модулями я имею ввиду /Разные/Нэймспэйсы и наборы классов) помогает делать проекты, которые удобно развивать как в одиночку, так и командами. Лишние пару строк на старте разработки нового функционала помогает экономить часы доработки.
P.S. Получилось немного сумбурно, я пытался от простого к сложному обосновать пользу понимания и использования классов, даже без каких-то лютых наследований и трейтов.
Прошу судить строго, так как это помогает двигаться вперёд.
UPD: я был не прав в том что не указал контекст.
Контекст - "при разработке масштабных продуктов на PHP"
