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

Почему классы лучше чем функции при разработке масштабных продуктов на PHP

Уровень сложностиПростой
Время на прочтение4 мин
Количество просмотров15K

Дисклэймер: мне нужно было объяснить моему сотруднику зачем нужны классы в принципе, а именно в чём их преимущество перед функциями. Я начал фантазировать примеры кода, и написал много комментариев. В итоге я посмотрел на то что получилось и подумал - а не дерзнуть ли в песочницу на Хабре?

Что такое хороший код?

  • Это востребованный код, то есть код который работает в живом проекте
    Это не сильно связанно с темой, но это нужно понимать, так как остальное следует из первого пункта

  • Это код, который работает с минимальным количеством ошибок

  • Это код, который удобно поддерживать и расширять (не важно, будет ли это делать один человек или команда разработчиков)

Классы помогают писать хороший код

Буду рассматривать классы не как необходимый инструмент парадигмы ООП, а как инструмент проектирования системы (и стараться доказать их преимущества перед функциями)

Читаемость

<?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"

Теги:
Хабы:
Всего голосов 37: ↑11 и ↓26-9
Комментарии124

Публикации

Истории

Ближайшие события

27 августа – 7 октября
Премия digital-кейсов «Проксима»
МоскваОнлайн
19 сентября
CDI Conf 2024
Москва
20 – 22 сентября
BCI Hack Moscow
Москва
24 сентября
Конференция Fin.Bot 2024
МоскваОнлайн
24 сентября
Astra DevConf 2024
МоскваОнлайн
25 сентября
Конференция Yandex Scale 2024
МоскваОнлайн
28 – 29 сентября
Конференция E-CODE
МоскваОнлайн
28 сентября – 5 октября
О! Хакатон
Онлайн
30 сентября – 1 октября
Конференция фронтенд-разработчиков FrontendConf 2024
МоскваОнлайн
3 – 18 октября
Kokoc Hackathon 2024
Онлайн