Для чистого, тестируемого и масштабируемого кода в фреймворке Laravel нужно использовать определенные практики. PHP очень гибкий, но любые отклонения усложняют код и снижают скорость обнаружения ошибок.
Разбираемся, как помогает Laravel, и называем нужные практики для создания приложений.
Что такое Laravel
Laravel — это популярный бесплатный фреймворк для языка программирования PHP с открытым исходным кодом, который ускоряет процесс разработки без потери качества. В нем используется паттерн MVC (Model View Controller), который делает язык более понятным и адаптированным. Еще его можно рассматривать как фреймворк для веб‑приложений с выразительным синтаксисом. Он упрощает общие задачи, которые есть в веб‑проектах и приложениях.
Историческая справка: Следует знать, что Laravel был создан на месте фреймворка CodeIgniter в качестве современной замены, поскольку ему не хватало важных основных функций: встроенной поддержки аутентификации и авторизации пользователей. С момента появления в 2011 году Laravel принес встроенную поддержку локализации, представлений, работы с сессиями, маршрутизации запроса к конкретному контроллеру и другие крутые возможности.
Проблемы PHP, которые решает Laravel
Гарантирует, что неавторизованные пользователи не имеют незаконного доступа к платным или защищенным ресурсам, и настраивает практически все из коробки.
Обработка ошибок предварительно настроена, и ошибки регистрируются в классе AppExceptionsHandler, но можно настроить это поведение с помощью метода withExceptions в файле bootstrap/app.php.
Laravel имеет несколько инструментов для решения проблем, связанных с неэффективностью разработки и развертывания приложений на PHP. Среди них такие инструменты, как Laravel Forge и Laravel Vapor, инструменты стартового набора — Laravel Breeze и многие другие.
Встроенный планировщик команд позволяет настраивать расписание внутри Laravel, решая проблему внедрения системы планирования задач.
Командная строка PHP Artisan автоматически выполняет повторяющиеся задачи программирования вместо разработчиков.
Технические уязвимости быстро обнаруживаются и устраняются командой поддержки благодаря большой базе пользователей и активному сообществу.
Laravel также имеет встроенные инструменты тестирования, такие как Pest и PHPUnit и функции, позволяющие проводить экспрессивное тестирование.
Управление уведомлениями и событиями исключительно через PHP бывает очень сложным, а Laravel предлагает пользователю специальную систему для ускорения процесса.
Laravel позволяет настроить маршрутизацию URL для упрощения конфигурации маршрутов, если вы хотите указать намерения пользователя, чтобы система понимала, куда он переходит.
Структура
Laravel придерживается архитектуры MVC, то есть взаимодействие происходит на View, а Controller обрабатывает запрос, получая данные через Model и возвращая ожидаемый ответ пользователю через View.
Получается, что когда клиент отправляет HTTP-запрос на сервер Laravel, сервер направляет запрос в Router, который направляет его в соответствующий Controller. Если определены Middlewares, запрос проходит через них прежде чем попасть в Controller. Controller вызывает необходимые модели и сервисы, необходимые для обработки запроса, и возвращает HTTP-ответ в виде представления.
Основные возможности Laravel
Laravel Eloquent ORM (Object Relational Mapping): Eloquent ORM — это пакет объектно-реляционного отображения для фреймворка Laravel, облегчающий взаимодействие с базой данных. Он является модельным компонентом структуры Laravel, позволяет представлять записи реляционных таблиц базы данных как объекты, а таблицы базы данных как модели. В результате практически не требуется взаимодействовать с базой данных с помощью SQL-запросов. Быстрее взаимодействовать с базой данных с помощью ORM.
Определите таблицы и связи между ними, а модель Eloquent сделает все остальное. Eloquent Model может выполнять синхронизацию нескольких баз данных, обновление, удаление, вставку и так далее.
Стандарты безопасности: структура фреймворка обеспечивает высокий уровень защиты, например, маркеры CSRF, которые гарантируют, что аутентифицированный пользователь — это тот, кто делает запрос к приложению. Кроме того, он защищает личные учетные данные с помощью алгоритмов хэширования. Laravel также хранит пароли в виде хэшированных и «соленых» хэшей, а не в виде обычного текста.
Движок шаблонов: Фреймворк поставляется со встроенным движком шаблонов Blade. Этот движок рендерит файлы.blade.php, содержащие HTML‑шаблоны и некоторые директивы Blade.
Работа с маршрутами: Фреймворк очень просто обрабатывает маршруты и может быть использован для создания единого интерфейса между вашими данными и клиентом, что делает его отличным кандидатом для Full API. Проще говоря, он позволяет выполнять запросы к определенному URL, например login, что полезно для социальных сетей и сайтов.
Аутентификация: Laravel имеет встроенные сервисы аутентификации и сессий, которые можно использовать через фасады Auth и Session. Он предлагает аутентификацию на основе cookie в большей степени для запросов, поступающих из браузера.
Работа с сессиями/кэшем: Laravel собирает запросы и хранит информацию о пользователе в таких хранилищах, как File, Redis, Memcached и так далее. Пользователи могут легко получить сохраненные элементы, поскольку они хранятся в быстрых и легкодоступных данных. Laravel предоставляет механизмы для компиляции активов со всеми тонкостями хранения и управления файлами. Такая обработка кэша повышает скорость работы приложения.
Юнит‑тестирование: Как и следует из названия, модульное тестирование выполняет проверку отдельных моделей и контроллеров для выявления проблем. Согласно документации Laravel, поддержка тестирования с помощью PHPUnit включена в комплект поставки, и файл phpunit.xml уже настроен для вашего приложения, когда вы начинаете работу.
Помимо перечисленных выше функций, Laravel обладает и другими дополнительными возможностями, такими как миграцией баз данных, планированием задач, очередями заданий и проверки запросов.
Для чего лучше использовать Laravel
Laravel, как PHP-фреймворк, является одним из лучших инструментов для создания различных веб-приложений, включая:
Пользовательские веб-приложения и сайты с большим количеством контента: Laravel — отличный выбор для создания приложений с большим количеством контента, например блогов (о том, как создать блог с помощью Laravel, читайте здесь). Он предлагает повышенную производительность и уникальный способ управления трафиком с помощью системы кэширования, которая сохраняет часто используемые данные и страницы, чтобы уменьшить затраты на их получение и компиляцию. Благодаря этому приложение работает быстрее и эффективнее.
Многоязычные приложения: Laravel позволяет создавать многоязычные приложения и обеспечивает бесперебойную работу пользователей независимо от языка. Его функция локализации позволяет легко управлять переводами. Это обеспечивает поддержку множества языков и делает ваше приложение более доступным.
Социальные сети: Это также отличный вариант для создания сайтов социальных сетей, поскольку в нем есть функция промежуточного ПО и строгая безопасность. Эта функция, которая по умолчанию доступна в Laravel, делает его лучшим инструментом для предоставления доступа к определенному сайту только настоящим пользователям.
Сайты электронной коммерции: Надежная система аутентификации делает его отличным выбором для создания сайтов электронной коммерции. Когда клиенты заходят на сайт, чтобы приобрести товар, Laravel гарантирует, что они смогут безопасно совершить транзакцию. Кроме того, его система аутентификации позволяет легко управлять доступом пользователей, обеспечивая покупателям безопасный и персонализированный опыт.
Разработка API: Сильная поддержка для разработки API делает его лучшим выбором для создания масштабируемых и поддерживаемых API. Встроенные функции, такие как маршрутизация, версионирование, обработка ошибок и безопасность, работают вместе, чтобы облегчить разработку API, позволяя разработчикам сосредоточиться на создании надежных и эффективных API. А благодаря функциям промежуточного ПО запросы и ответы могут быть изменены или преобразованы в нужный формат.
Приложения в реальном времени: Laravel позволяет легко создавать приложения, работающие в режиме реального времени, с помощью такого инструмента, как Echo. Двусторонняя связь между сервером и клиентом очень важна для таких функций, как обновления в реальном времени, чат‑системы и инструменты для совместной работы. PresenceChannel, функция Laravel Echo, также позволяет отслеживать присутствие и активность пользователей в режиме реального времени, что упрощает создание функций совместной работы.
Лучшие практики для разработчиков в 2024 году
В этом разделе мы рассмотрим основные практики работы с Laravel, включая практики работы с API, со структурой проекта и контроллерами. Следуя этим рекомендациям, вы сможете писать чистый, эффективный и поддерживаемый код по всем стандартам.
Всегда используйте самый стабильный релиз
Самую последнюю версию — Laravel 11.x, выпустили 12 марта 2024 года. Этот новый релиз включает в себя несколько важных обновлений:
Opt-in API и broadcast routing: До версии 11, когда вы создавали новый проект Laravel, он сам настраивал API и broadcast routing. Но в Laravel 11 эти маршруты являются опциональными и могут быть добавлены с помощью команды artisan:
php artisan install:api
php artisan install:broadcasting
Обязательно следуйте новому процессу, который описан в документации к релизу.
Упрощенный базовый класс контроллера: Удалены трейты AuthorizesRequests и ValidatesRequests. Если они вам нужны, вам придется добавить их вручную. Кроме того, базовый класс контроллера больше не расширяет внутренний класс.
Храните бизнес-логику в классе сервиса
Чтобы обеспечить чистоту кода, пользователи должны реализовывать абстракции. Хотя контроллеры обычно управляют бизнес-логикой, бывают случаи, когда эта логика может потребоваться для повторного использования другими контроллерами. Тогда целесообразно инкапсулировать эту логику в отдельных классах служб. Такой подход помогает поддерживать чистоту кода, избегая избыточности и способствуя повторному использованию.
Вот пример плохого подхода, когда бизнес-логика тесно связана с контроллером и не может быть использована повторно:
namespace App\Http\Controllers;
...
class OrderController extends Controller
{
public function placeOrder(Request $request)
{
$data = $request->all();
$user = User::find($data['user_id']);
$order = new Order();
$order->user_id = $user->id;
$order->total = $data['total'] + ( $data['total'] * 0.5);
$order->status = 'pending';
$order->save();
// ...
}
. . .
}
Этот сниппет создает запись о заказе, используя данные пользователя и данные из запроса. Он также вычисляет общую стоимость заказа.
Чтобы сделать это лучше, вам нужно будет рефакторить код, чтобы он выглядел следующим образом:
namespace App\Services;
...
class OrderService
{
public function createOrder(array $orderData)
{
// Encapsulated business logic
$user = User::find($orderData['user_id']);
$order = new Order();
$order->user_id = $user->id;
$order->total = $data['total'] + ( $data['total'] * 0.5);
$order->status = 'pending';
$order->save();
return $order;
}
}
Затем внедрите службу в контроллер, как показано ниже:
...
use App\Services\OrderService;
class OrderController extends Controller
{
private $orderService;
public function __construct(OrderService $orderService)
{
$this->orderService = $orderService;
}
public function placeOrder(Request $request)
{
$orderData = $request->all();
$order = $this->orderService->createOrder($orderData);
// ...
}
}
Используйте вспомогательные функции
Laravel поставляется с несколькими вспомогательными функциями и методами. Вместо того чтобы изобретать велосипед, лучше использовать существующие методы, так как это позволит сохранить лаконичность кодовой базы и избежать повторений. Типичный пример — когда нужно сгенерировать случайную строку. Вместо того чтобы создавать новую функцию для этого, вы можете использовать Illuminate/Support/Str
и сделать следующее:
$slug = Str::random(24);
Эти помощники доступны в любом месте приложения.
Соблюдайте принцип единой ответственности (SRP)
Класс и метод должны нести только одну ответственность. Это упрощает реализацию программного обеспечения и предотвращает любые непредвиденные побочные эффекты из-за изменений, которые произойдут в будущем.
Например, вместо метода, который возвращает данные транзакции, выполняется несколько операций, как показано в приведенном ниже фрагменте:
public function getTransactionAttribute()
{
if ($transaction && ($transaction->type == 'withdrawal') && $transaction->isVerified()) {
return ['reference'=>$this->transaction->reference, 'status'=>'verified'];
} else {
return ['link'=>$this->transaction->paymentLink, 'status'=>'not verified'];
}
}
Чтобы улучшить читаемость, распределите действия по методам следующим образом:
public function getTransactionAttribute(): bool
{
return $this->isVerified() ? $this->getReference() : $this->getPaymentLink();
}
public function isVerified(): bool
{
return $this->transaction && ($transaction->type == 'withdrawal') && $this->transaction->isVerified();
}
public function getReference(): string
{
return ['reference'=>$this->transaction->reference, 'status'=>'verified'];
}
public function getPaymentLink(): string
{
return ['link'=>$this->transaction->paymentLink, 'status'=>'not verified'];
}
Используйте инструмент Artisan CLI
В инструменте artisan CLI есть множество команд, которые помогут создать нужную вам настройку. Например, вместо того чтобы вручную писать файлы миграции и создавать модель, используйте команду:
php artisan make:model Branding -m
Есть еще несколько команд, которые можно использовать в Artisan, в том числе:
Команда «Создать запрос».
php artisan make:request LoginRequest
Команда оптимизации, с помощью которой можно очистить кэш.
php artisan optimize:clear
Команда для запуска миграций
php artisan migrate
Также команда для запуска тестов
php artisan test
Более подробную информацию вы можете найти в документации Laravel.
Выполняйте проверку в классах запросов
Валидация очень важна при обработке пользовательского ввода в вашем приложении, чтобы обеспечить согласованность данных и предотвратить ошибки. Встраивание правил валидации в методы контроллера может стать громоздким и повторяющимся. Чтобы решить эту проблему, Laravel предоставляет классы FormRequest, которые позволяют централизованно и многократно использовать правила валидации.
Раньше вы могли писать правила валидации непосредственно в методе контроллера, например, так:
public function store(Request $request)
{
$request->validate([
'slug' => 'required',
'title' => 'required|unique:posts|max:255',
...
]);
}
Вместо этого создайте специальный класс FormRequest с помощью инструмента artisan CLI:
php artisan make:request StoreRequest
В этом классе определите правила валидации:
class StoreRequest extends FormRequest
{
...
public function rules(): array
{
return [
'slug' => 'required',
'title' => 'required|unique:posts|max:255',
...
];
}
}
Затем обновите метод контроллера, чтобы он использовал созданный вами класс FormRequest
:
public function store(StoreRequest $request)
{
...
}
Используя классы FormRequest
, вы можете отделить логику проверки от контроллера и повторно использовать эти правила во всем приложении. Такой подход способствует более чистому коду, уменьшает дублирование и упрощает обслуживание.
Таймаут HTTP-запроса
Одна из лучших практик Laravel — использование таймаутов. Вы можете избежать ошибок при отправке HTTP-запросов из вашего контроллера. По умолчанию Laravel устанавливает таймаут для запросов к серверу через 30 секунд. Если HTTP-запрос задерживается, а сообщения об ошибке нет, ваше приложение может зависнуть на неопределенное время.
Вот пример того, как сделать таймаут HTTP-запроса через 120 секунд.
public function store(StoreRequest $request)
{
....
$response = Http::timeout(120)->get(...);
....
}
Используйте преимущества массовых назначений
В Laravel массовые назначения помогают избегать ситуаций, когда пользователи могут непреднамеренно изменить конфиденциальные данные, например, пароли или статус администратора. Предположим, что у вас есть продукт, который вы хотите сохранить в модели Product. Вы можете использовать следующий код:
$product = new Product;
$product->name = $request->name;
$product->price = $request->price;
$product->save();
А еще есть статический метод create
из класса модели, который передает массив подтвержденных запросов следующим образом;
Product::create($request->validated());
Разбивка данных на куски для задач с большими объемами данных
При обработке большого количества информации из базы данных можно извлекать ее и выполнять цикл, как это сделано здесь:
$products = Product::all() /* returns thousands of data */
foreach ($products as $product) {
...
}
Используйте метод chunk
, указывая фиксированное количество, которое вы хотите обработать за раз, и закрытие для обработки. Вот пример:
Product::chunk(200, function ($products) {
foreach ($products as $product) {
// Perform some action on the product
}
});
Не используйте переменные окружения (.env) непосредственно в коде
В Laravel используйте env(...) в файлах конфигурации для определения значений и config(...) в коде приложения для их получения. Это обеспечивает совместимость с системой кэширования конфигураций.
Например, если вам нужно использовать внешний сервис, требующий API-ключей, он должен быть безопасным. Поэтому вы добавляете ключ в хранилище ключей (файл .env). Вместо того, чтобы получать ключи напрямую, можно поступить следующим образом:
$chat_gpt_key = env("CHAT_GPT_API_KEY");
Лучше всего добавить его в файл config/api.php, используя:
[
...
'chat_gpt_key' => env("CHAT_GPT_API_KEY"),
]
Затем, когда вам понадобится использовать ключ в любом разделе вашего проекта, просто возьмите его с помощью функции config, предоставляемой Laravel.
$chat_gpt_key = config('api.chat_gpt_key');
Это дает вам больше контроля над переменной окружения, позволяя установить значение по умолчанию, даже если переменная окружения не существует в вашем хранилище ключей (файл .env). А еще использование метода config имеет преимущества в производительности, ведь Laravel кэширует конфигурации, которые есть в конфигурационных файлах.
Используйте Eloquent вместо Query Builder и необработанных SQL-запросов
Eloquent позволяет писать читаемый и поддерживаемый код. В нем есть полезные инструменты — soft deletes, events, scopes и т. д., и вы сможете задавать условия для запросов к таблицам базы данных, чтобы данные в таблице оставались корректными. Упрощает управление отношениями между моделями.
Вам не нужно писать сложный SQL-код, когда у вас есть Eloquent. Например, если вы хотите получить список товаров и их категорий, отфильтровать их по наличию и отсортировать по последним. Вместо того, чтобы использовать SQL-запрос следующего вида:
SELECT *
FROM `products`
WHERE EXISTS (SELECT *
FROM `categories`
WHERE `products`.`category_id` = `categories`.`id`
AND `categories`.`deleted_at` IS NULL)
AND `is_available` = '1'
ORDER BY `created_at` DESC
Просто используйте это:
Product::has('category')->isAvailable()->latest()->get();
Оба фрагмента кода извлекают продукты, которые имеют связанную категорию, отмечены как доступные и отсортированы в порядке убывания по времени создания. В то время как в первом фрагменте используется необработанный SQL, во втором — для применения этих условий используется цепочка методов Eloquent, что делает замысел кода более явным и простым для понимания.
Соблюдайте соглашения об именовании
Следуйте стандартам PSR, как указано здесь, а также используйте соглашения об именовании, которые помогут в организации ваших файлов. Использование последовательных соглашений очень важно, поскольку несоответствия могут привести к путанице, что в конечном итоге приведет к ошибкам. Ниже приведено табличное руководство.
Избегайте использования блоков комментариев к документации (DocBlocks)
Снижайте потребность в дополнительной документации, стараясь писать ясный и понятный код. Такой подход делает ваш код чище, читабельнее и удобнее для сопровождения.
Хорошо названный метод или класс часто может служить собственной документацией, избавляя от необходимости использовать блоки DocBlocks. Например:
public function calculateTotalOrderCost(Order $order): float
{
// Calculate and return the total cost
}
В данном примере название метода calculateTotalOrderCost
четко указывает на его назначение, что делает ненужной дополнительную документацию.
Используйте стандартные инструменты Laravel
Laravel предлагает ряд инструментов для улучшения разработки:
Sanctum: Упрощает аутентификацию и авторизацию;
Socialite: Упрощает аутентификацию в социальных сетях;
Jetstream: Ускоряет создание скелета приложения и предоставляет готовые компоненты пользовательского интерфейса;
Mix: Оптимизация компиляции и управления активами;
Эти инструменты стандартизируют ваш код, делают его удобным для сопровождения и регулярно обновляются при поддержке сообщества.
Используйте более короткий и читабельный синтаксис в коде
Использование более короткого синтаксиса делает ваш код последовательным, а еще снижает когнитивную нагрузку. Например, если вы хотите получить данные конкретной сессии из сессии запроса, можно использовать следующее:
$request->session()->get('order')
или
Session::get('order')
Просто используйте это:
session('order')
Реализация метода миграции
down()
Большинство разработчиков часто упускают из виду реализацию метода down()
в файле миграции. Такое пренебрежение может иметь значительные последствия, особенно при успешном выполнении откатов. Поэтому рекомендуется всегда реализовывать метод down()
для каждого метода up()
в файле миграции.
Например, если у вас есть файл миграции таблицы заказов, который создает новый столбец, fee
:
return new class extends Migration
{
public function up()
{
Schema::table('orders', function (Blueprint $table) {
$table->unsignedInteger('fee')->default(0);
});
}
...
};
Вам нужно реализовать метод down(
, который отменяет создание платы за столбец:
return new class extends Migration
{
public function up()
{
. . .
}
public function down()
{
Schema::table('orders', function (Blueprint $table) {
$table->dropColumn('fee');
});
}
}
Дополнительные практики, о которых следует помнить
Помимо рассмотренных выше практик, существуют дополнительные, которые улучшают читаемость и сопровождаемость кодовой базы. К ним относятся:
Практики Laravel для API:
Используйте промежуточное ПО для реализации авторизации и разрешений для конечных точек API. Это обеспечит централизованный контроль над кодовой базой и улучшит масштабируемость.
Применяйте версионность API, чтобы иметь возможность поддерживать различные версии конечных точек и внедрять обновления, не мешая существующим интеграциям.
Сериализация моделей должна осуществляться с помощью ресурсов API Eloquent, которые соответствуют лучшим практикам API-ответов Laravel. Это обеспечивает эффективный и поддерживаемый подход к управлению ответами API, давая вам больше контроля и многократно используемое решение.
Структуры проекта:
Соблюдайте структуру каталогов Laravel. Это позволит вам легко находить и отлаживать ваше приложение.
Внедряйте модульность, разбивая большие приложения на более мелкие, управляемые модули, чтобы повысить ремонтопригодность и масштабируемость.
Использование контроллеров:
Используйте контроллеры ресурсов Laravel для определения Full-маршрутов и методов для CRUD-операций, обеспечивая чистые и предсказуемые конечные точки API, когда это необходимо.
Вставляйте зависимости в контроллеры вместо их непосредственного инстанцирования. Это способствует развязке, делая ваш код более тестируемым и гибким.
Кэширование:
Используйте теги кэша и стратегии аннулирования кэша, чтобы эффективно управлять кэшированными данными и предотвращать появление устаревшей или неактуальной информации.
Одна из лучших практик Laravel в области REST API включает в себя кэширование регулярно используемых данных, которые редко меняются. Это уменьшает накладные расходы на поиск в базе данных.
Тестирование:
Проводите интеграционные тесты для проверки взаимодействия между различными частями вашего приложения, включая операции с базой данных, запросы к API и интеграцию внешних сервисов.
Структурируйте тесты, используя паттерн Arrange-Act-Assert (AAA). Это повышает читабельность и удобство сопровождения.
Будущее Laravel
Laravel, один из самых популярных PHP-фреймворков и уже 11 версия, скорее всего, будет продолжать развиваться и расти в обозримом будущем. Вот некоторые интересные возможности, которые могут определить будущее Laravel:
Более глубокое внедрение облачных нативных технологий, таких как бессерверная архитектура.
Laravel может открыто принять GraphQL, позволяя разработчикам создавать свои GraphQL API.
Значительные улучшения существующих инструментов в экосистеме, а также появление новых инструментов для улучшения опыта разработчиков и так далее.