Laravel — Хелперы и методы
Практический справочник по повседневным хелперам Laravel: что делает каждый, пример кода и use case. Покрывает 95% задач разработки.
Laravel поставляется с десятками helper-функций и статических методов, которые экономят сотни строк кода. Они покрывают: работу с запросами, валидацию, Eloquent-запросы, коллекции, строки, массивы, даты, сессии, авторизацию, маршруты, отладку.
request(), now(), collect()) или статический метод фасада (Str::slug(), Arr::get()), доступные где угодно — в контроллерах, моделях, Blade, командах.
Этот раздел структурирован так, чтобы каждый helper было видно с тремя пунктами: что делает, пример кода, use case (когда применять).
| Категория | Что покрывает | Примеры |
|---|---|---|
| Request | Чтение входных данных | request(), input(), filled(), old() |
| Validation | Проверка входных данных | required, email, unique, Rule::in(), sometimes |
| Eloquent | Запросы к БД | where(), find(), with(), whereHas(), paginate() |
| Collections | Работа с массивами на стероидах | map(), filter(), reduce(), groupBy() |
| Str | Строки | Str::slug(), limit(), contains(), random() |
| Arr | Массивы | Arr::get(), only(), except(), set() |
| Carbon | Даты и время | now(), addDays(), diffForHumans() |
| Auth/Session | Сессии и пользователь | auth(), session(), bcrypt() |
| Routing | URL и редиректы | route(), url(), redirect(), asset() |
| Debug | Отладка | dd(), dump(), abort(), config() |
| Artisan | CLI команды | migrate, make:model, tinker |
Чтение данных из формы, query-параметров, JSON-тела. В Laravel нет прямой работы с $_GET/$_POST — всё через объект Request или global helper request().
request() / $request->input()
Получить любое поле из запроса (form, JSON, query). Второй аргумент — значение по умолчанию.
public function store(Request $request)
{
$name = $request->input('name'); // из формы/JSON
$email = request('email'); // то же через helper
$role = $request->input('role', 'guest'); // default
}
$request->all() / only() / except()
Получить весь массив входных данных или его подмножество.
$data = $request->all(); // все поля
$creds = $request->only(['email', 'password']); // только нужные
$safe = $request->except(['_token', 'password']); // без указанных
Model::create($request->only([...])) — безопасный mass-assign только нужных полей.filled()
true, если поле есть и не пустое (не null, не '', не []).
if ($request->filled('phone')) {
sendSMS($request->input('phone'));
}
has()
true, если поле присутствует в запросе (даже если пустая строка).
if ($request->has('promo_code')) {
applyDiscount($request->input('promo_code'));
}
?promo_code=.old()
Возвращает старое значение поля из flash-сессии — сохраняет ввод формы после ошибки валидации.
<!-- В Blade -->
<input type="email" name="email" value="{{ old('email') }}">
$model->fill($request->all())
Заполняет атрибуты модели из массива (без сохранения). Соблюдает $fillable.
public function update(Request $request, User $user)
{
$user->fill($request->validated());
$user->save();
}
$user->update($data) делает то же самое в одну строку.90% задач валидации решаются комбинацией этих правил. Применяются через $request->validate([...]) или в FormRequest::rules().
$validated = $request->validate([
'email' => 'required|email|unique:users,email',
'password' => 'required|confirmed|min:8',
]);
required
Поле должно присутствовать и не быть пустым.
'email' => 'required',
nullable
Разрешает null или отсутствие поля. Часто комбинируется с типом.
'middle_name' => 'nullable|string|max:100',
nullable правило string отвергнет null.email
Валидный email-формат. Опции: email:rfc,dns (проверка DNS).
'email' => 'required|email',
'email' => 'required|email:rfc,dns', // строже
numeric / integer
numeric — любое число (вкл. дробные), integer — только целое.
'price' => 'required|numeric|min:0',
'quantity' => 'required|integer|min:1',
regex:/pattern/
Кастомный шаблон через регулярное выражение.
'username' => ['required', 'regex:/^[a-zA-Z0-9_]+$/'],
'phone' => ['required', 'regex:/^\+?[0-9]{10,15}$/'],
min / max
Для строк — длина, для чисел — значение, для файлов — размер в KB, для массивов — кол-во элементов.
'username' => 'required|min:3|max:20', // 3–20 символов
'age' => 'integer|min:18', // число ≥ 18
'photo' => 'file|max:2048', // до 2 МБ
unique:table,column
Значение уникально в указанной таблице/колонке. При обновлении исключи текущую запись.
// При создании
'email' => 'required|email|unique:users,email',
// При обновлении (исключить текущего юзера по id)
'email' => ['required', 'email', Rule::unique('users')->ignore($user->id)],
exists:table,column
Проверяет, что значение существует в указанной таблице. Применяется к foreign key'ам.
'category_id' => 'required|exists:categories,id',
Rule::in([...])
Значение должно быть в списке разрешённых. Аналог enum.
use Illuminate\Validation\Rule;
'status' => ['required', Rule::in(['draft', 'published', 'archived'])],
confirmed
Требует наличия поля {field}_confirmation с тем же значением.
'password' => 'required|confirmed|min:8',
// В форме нужны: password И password_confirmation
Дополнительный арсенал для дат, массивов, файлов и условной валидации.
date
Валидная дата (любой формат, который понимает PHP strtotime).
'birthday' => 'required|date',
'event' => 'required|date_format:Y-m-d H:i', // строгий формат
before / after
Сравнение дат. Может ссылаться на другое поле или константу типа today.
'start_date' => 'required|date',
'end_date' => 'required|date|after:start_date',
'birthday' => 'required|date|before:today',
sometimes
Правило применяется только если поле присутствует в запросе. Иначе — игнорируется.
'phone' => 'sometimes|numeric|digits_between:10,15',
array + field.*
Поле — массив. Через tags.* валидируется каждый элемент.
'tags' => 'required|array|min:1',
'tags.*' => 'string|max:30',
distinct
Элементы массива должны быть уникальными.
'emails' => 'array',
'emails.*' => 'email|distinct',
json
Строка должна быть валидным JSON.
'metadata' => 'required|json',
boolean
Принимает: true, false, 1, 0, "1", "0".
'is_active' => 'required|boolean',
ip / url / active_url
Сетевые форматы. active_url проверяет, что домен реально резолвится.
'server_ip' => 'required|ip',
'website' => 'required|url',
'callback' => 'required|active_url',
mimes / mimetypes
Тип загружаемого файла. mimes — по расширению, mimetypes — по MIME.
'avatar' => 'required|image|mimes:jpg,png,webp|max:2048',
'document' => 'required|mimetypes:application/pdf|max:5120',
FormRequest:
class StoreUserRequest extends FormRequest
{
public function rules(): array
{
return [
'name' => 'required|string|max:100',
'email' => 'required|email|unique:users',
'password' => 'required|confirmed|min:8',
];
}
}
Методы query builder'а, доступные на любой модели и её отношениях.
where() / orWhere()
Базовые условия WHERE. orWhere добавляет OR-ветку.
User::where('status', 'active')->get();
User::where('age', '>', 18)
->orWhere('role', 'admin')
->get();
whereIn() / whereNotIn()
WHERE IN (...) — поиск по списку значений.
User::whereIn('id', [1, 2, 3])->get();
Post::whereNotIn('status', ['draft', 'deleted'])->get();
request()->input('ids')).find() / findOrFail()
Поиск по первичному ключу. findOrFail бросает 404.
$user = User::find(5); // null если не найден
$user = User::findOrFail(5); // 404 если не найден
findOrFail избавляет от ручной проверки if (!$user) abort(404).first() / firstOrFail()
Первая запись по условию. firstOrFail бросает 404.
$user = User::where('email', $email)->first();
$user = User::where('email', $email)->firstOrFail();
orderBy() / latest() / oldest()
Сортировка. latest() — алиас orderBy('created_at', 'desc').
Post::orderBy('created_at', 'desc')->get();
Post::latest()->take(10)->get(); // 10 свежих
take() / limit()
Ограничить число записей.
User::orderBy('id', 'desc')->take(5)->get();
paginate()
Готовая пагинация: возвращает LengthAwarePaginator с навигацией.
$posts = Post::latest()->paginate(10);
// В Blade:
{{ $posts->links() }}
pluck()
Извлечь одну колонку. Опционально — построить key=>value мапу.
$emails = User::pluck('email'); // [email, email, ...]
$options = User::pluck('name', 'id'); // [id => name]
<select>, списки email'ов для рассылки.with() — eager loading
Подгружает связанные модели одним запросом — спасает от N+1 проблемы.
// Плохо (N+1):
foreach (User::all() as $u) {
echo $u->posts->count(); // +1 запрос на каждого юзера
}
// Хорошо (2 запроса всего):
foreach (User::with('posts')->get() as $u) {
echo $u->posts->count();
}
whereHas()
Фильтрация по связанной модели — «есть ли подходящие related».
// Пользователи, у которых есть хотя бы один опубликованный пост
User::whereHas('posts', function ($q) {
$q->where('status', 'published');
})->get();
count() / exists() / doesntExist()
Количество или булевая проверка существования без загрузки моделей.
$total = User::where('active', true)->count();
if (User::where('email', $email)->exists()) { ... }
Все Eloquent-результаты (get(), all()) возвращают Collection. Любой массив можно обернуть через collect(). Методы chain'аются и не мутируют исходное.
collect()
Обёртка над массивом — открывает все методы коллекции.
$nums = collect([1, 2, 3, 4, 5]);
$nums->filter(fn($n) => $n % 2 === 0)->values(); // [2, 4]
foreach, используй коллекции.map()
Трансформирует каждый элемент. Возвращает новую коллекцию.
$prices = collect([100, 200, 300]);
$withTax = $prices->map(fn($p) => $p * 1.12);
// [112, 224, 336]
reduce()
Свёртка коллекции в одно значение (аккумулятор).
$total = collect([100, 250, 50])
->reduce(fn($carry, $x) => $carry + $x, 0);
// 400
sum() не справляется.sum() / avg() / max() / min()
Базовые агрегаты. Можно передать ключ объекта.
$invoices->sum('amount'); // сумма всех amount
$grades->avg(); // среднее
$products->max('price'); // макс
groupBy()
Группирует элементы по ключу или результату функции.
$users->groupBy('role');
// ['admin' => [...], 'editor' => [...]]
$orders->groupBy(fn($o) => $o->created_at->format('Y-m'));
pluck()
То же, что в Eloquent — извлечь одно поле из всех элементов.
$names = $users->pluck('name');
$map = $users->pluck('email', 'id');
sortBy() / sortByDesc()
Сортировка коллекции (без модификации БД-запроса).
$products->sortBy('price');
$products->sortByDesc('created_at');
filter()
Оставляет только элементы, удовлетворяющие условию.
$active = $users->filter(fn($u) => $u->is_active);
contains()
Проверяет наличие значения в коллекции.
$emails->contains('a@gmail.com'); // true/false
$users->contains('role', 'admin'); // есть ли админ
where() / whereIn() на коллекции
Фильтрация коллекции по ключу/значению (не путать с Eloquent-запросом).
$over30 = $users->where('age', '>', 30);
$admins = $users->whereIn('role', ['admin', 'owner']);
chunk() / each()
Разбивка на куски / итерация.
$users->chunk(100)->each(function ($chunk) {
processBatch($chunk);
});
Str хелперыФасад Illuminate\Support\Str — все строковые операции. Часть из них дублирует встроенные PHP-функции, но единообразнее и с поддержкой Unicode.
Str::slug()
URL-friendly slug из строки.
Str::slug('Laravel Framework Basics!');
// "laravel-framework-basics"
Str::slug('Привет мир', '-', 'ru');
// "privet-mir"
Str::limit()
Обрезает строку, добавляет «…» (или кастомный суффикс).
Str::limit('Laravel is awesome framework', 10);
// "Laravel is..."
Str::contains() / startsWith() / endsWith()
Подстроковые проверки.
Str::contains('user@gmail.com', '@gmail.com'); // true
Str::startsWith('https://site.com', 'https'); // true
Str::endsWith('report.pdf', '.pdf'); // true
Str::random()
Криптостойкая случайная строка указанной длины.
$token = Str::random(32);
// "d8ks92j3lqp93jf02ldk9as8dj29dkfj"
Str::replace()
Замена всех вхождений (или массива).
Str::replace('Java', 'Laravel', 'I love Java.');
// "I love Laravel."
Str::upper() / lower() / title()
Регистровые преобразования с поддержкой Unicode.
Str::upper('laravel'); // "LARAVEL"
Str::lower('LARAVEL'); // "laravel"
Str::title('hello world'); // "Hello World"
Str::camel() / snake() / kebab() / studly()
Конвертация между стилями именования.
Str::camel('hello_world'); // "helloWorld"
Str::snake('HelloWorld'); // "hello_world"
Str::kebab('HelloWorld'); // "hello-world"
Str::studly('hello_world'); // "HelloWorld" (PascalCase)
Str::uuid() / Str::ulid()
Генерация UUID v4 / ULID (сортируемый по времени).
$id = (string) Str::uuid();
// "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
$id = (string) Str::ulid();
Arr хелперыФасад Illuminate\Support\Arr — операции над PHP-массивами с поддержкой dot-notation для вложенных ключей.
Arr::get()
Безопасное чтение по dot-пути. Не падает на отсутствующих ключах.
$data = ['user' => ['profile' => ['email' => 'a@x.com']]];
Arr::get($data, 'user.profile.email'); // "a@x.com"
Arr::get($data, 'user.profile.phone', 'N/A'); // "N/A"
isset().Arr::has()
Проверка существования по dot-пути.
if (Arr::has($data, 'user.profile.email')) { ... }
Arr::only() / Arr::except()
Whitelist / blacklist ключей.
Arr::only($user, ['id', 'name', 'email']);
Arr::except($user, ['password', 'token']);
Arr::set() / Arr::forget()
Установка / удаление по dot-пути. Создаёт вложенные структуры при необходимости.
$data = [];
Arr::set($data, 'user.profile.email', 'a@x.com');
// ['user' => ['profile' => ['email' => 'a@x.com']]]
Arr::forget($data, 'user.profile.email');
Arr::pluck()
Извлечь колонку из массива объектов/массивов.
Arr::pluck($users, 'email');
Arr::pluck($users, 'email', 'id'); // [id => email]
Arr::first() / Arr::last()
Первый/последний элемент, опц. по условию.
Arr::first([10, 20, 30], fn($v) => $v > 15); // 20
Arr::flatten() / Arr::collapse()
Сплющивание вложенных массивов.
Arr::flatten([['a','b'], ['c']]); // ['a','b','c']
Arr::collapse([[1,2], [3,4]]); // [1,2,3,4]
Arr::wrap()
Если не массив — обернёт в массив. null → [].
Arr::wrap('apple'); // ['apple']
Arr::wrap(['a', 'b']); // ['a', 'b']
Arr::wrap(null); // []
Arr::random()
Случайный элемент (или несколько).
Arr::random(['red', 'blue', 'green']);
Arr::random(['red', 'blue', 'green'], 2); // 2 случайных
Все даты в Laravel — Carbon\Carbon (расширение PHP DateTime). Eloquent timestamps (created_at, updated_at) тоже Carbon-инстансы.
now() / today()
Текущее время / начало текущего дня (00:00:00).
now(); // 2026-05-14 18:35:42
today(); // 2026-05-14 00:00:00
addDays() / subDays() / addHours() / subMinutes()
Математика над датами. Возвращает новый Carbon-инстанс (chainable).
now()->addDays(7); // +7 дней
now()->subHours(2); // -2 часа
now()->addMonths(3)->endOfDay(); // +3 месяца, конец дня
format()
Формат вывода (через стандартные PHP-токены: Y, m, d, H, i, s).
now()->format('d/m/Y H:i'); // "14/05/2026 18:35"
now()->format('Y-m-d'); // "2026-05-14"
diffForHumans()
Человеко-читаемое расхождение: «5 минут назад», «in 3 days».
now()->subMinutes(10)->diffForHumans();
// "10 minutes ago"
now()->addDays(3)->diffForHumans();
// "in 3 days"
Carbon::parse()
Парсинг строки в Carbon-объект.
use Carbon\Carbon;
$date = Carbon::parse('2026-12-31 23:59:59');
$date->format('l, d M Y'); // "Thursday, 31 Dec 2026"
isPast() / isFuture() / isToday()
Булевые проверки.
if ($user->trial_ends_at->isPast()) {
deactivate($user);
}
session()
Чтение / запись сессии. Без аргументов — возвращает менеджер.
session(['cart_count' => 5]); // записать
$count = session('cart_count', 0); // читать с default
session()->forget('cart_count'); // удалить
session()->flash()
Сохраняет значение только на следующий запрос.
session()->flash('status', 'Profile updated!');
// эквивалент: redirect()->with('status', '...')
// В Blade на следующей странице:
@if(session('status'))
<div class="alert">{{ session('status') }}</div>
@endif
auth()->user() / auth()->id()
Текущий аутентифицированный юзер (модель) или его ID.
$user = auth()->user();
$userId = auth()->id();
// shortcut в Blade:
@auth
Привет, {{ auth()->user()->name }}
@endauth
created_by => auth()->id()), персонализация UI.auth()->check() / auth()->guest()
Аутентифицирован или нет.
if (auth()->check()) {
// залогинен
}
if (auth()->guest()) {
return redirect()->route('login');
}
bcrypt() / Hash::make()
Хэширование пароля. Алгоритм bcrypt с salt.
User::create([
'email' => $request->input('email'),
'password' => bcrypt($request->input('password')),
]);
// При логине — Hash::check() сравнивает без расхэширования:
Hash::check($plain, $user->password);
Auth::attempt() / Auth::logout()
Логин по credentials и выход из сессии.
if (Auth::attempt([
'email' => $request->email,
'password' => $request->password,
])) {
$request->session()->regenerate(); // защита от session fixation
return redirect()->intended('/');
}
Auth::logout();
route()
URL по имени маршрута. Параметры подставляются автоматически.
// routes/web.php
Route::get('/posts/{post}', [PostController::class, 'show'])->name('posts.show');
// В контроллере / Blade
route('posts.show', $post); // /posts/5
route('posts.show', ['post' => 5]); // /posts/5
url()
Абсолютный URL из пути.
url('/contact'); // https://site.com/contact
url()->current(); // URL текущей страницы
url()->previous(); // referrer
asset()
URL к файлу в public/.
<link rel="stylesheet" href="{{ asset('css/app.css') }}">
<img src="{{ asset('img/logo.png') }}">
@vite().view()
Рендеринг Blade-шаблона с данными.
return view('posts.show', [
'post' => $post,
'comments' => $post->comments,
]);
redirect()
HTTP-редирект. Поддерживает имена маршрутов, обратные ссылки, flash-данные.
return redirect('/dashboard');
return redirect()->route('home');
return redirect()->back()->with('error', 'Wrong data');
return redirect()->intended('/'); // после login — туда, куда хотел юзер
back()
Алиас redirect()->back().
return back()->withErrors($validator)->withInput();
response()->json()
JSON-ответ с правильными заголовками.
return response()->json([
'status' => 'ok',
'data' => $user,
], 200);
dd() — dump & die
Печатает значение и завершает выполнение.
dd($user);
dd($request->all(), $user); // можно несколько
dump()
Печатает, но не останавливает выполнение.
dump($step1);
dump($step2);
return view('page'); // выполнение продолжится
abort()
Прервать запрос с HTTP-ошибкой.
abort(404);
abort(403, 'Доступ запрещён');
abort_if(!auth()->user()->isAdmin(), 403);
abort_unless($user->active, 403);
throw_if() / throw_unless()
Условный throw — компактнее, чем if + throw.
throw_if($user->balance < 0, InsufficientFundsException::class);
throw_unless($user->verified, UnverifiedException::class);
config()
Чтение / запись конфигурации (из config/*.php).
config('app.name'); // чтение
config(['app.name' => 'NewApp']); // запись (на runtime)
config('services.stripe.key');
config(), а не прямой env() в коде — конфиги кешируются.env()
Чтение из .env. Работает только если config:cache НЕ запущен.
env('APP_ENV'); // "local" / "production"
env('STRIPE_KEY', 'default');
config/*.php файлах. В контроллерах используй config().tap()
Выполняет действие над объектом и возвращает сам объект.
return tap(User::create($data), function ($user) {
$user->sendWelcomeEmail();
}); // вернёт $user (а не результат sendWelcomeEmail)
cache()
Чтение / запись кэша.
cache(['key' => 'value'], now()->addMinutes(10));
cache('key', 'default');
// Remember pattern — если нет, вычислить и сохранить:
Cache::remember('users.count', 60, fn() => User::count());
Командная строка Laravel. Все артефакты (контроллеры, модели, миграции) генерируются командой.
| Команда | Что делает |
|---|---|
php artisan make:model Post -mfsc | Модель + миграция + factory + seeder + controller |
php artisan make:controller PostController --resource | Resource controller (7 методов CRUD) |
php artisan make:request StorePostRequest | FormRequest для валидации |
php artisan make:migration create_posts_table | Новая миграция |
php artisan make:seeder PostSeeder | Seeder |
php artisan make:factory PostFactory --model=Post | Factory |
php artisan make:middleware EnsureUserIsAdmin | Middleware |
php artisan make:job ProcessPayment | Job для очереди |
php artisan make:notification InvoicePaid | Notification |
php artisan make:mail OrderShipped | Mailable |
php artisan make:event OrderPlaced | Event |
php artisan make:listener SendOrderEmail --event=OrderPlaced | Listener |
php artisan make:policy PostPolicy --model=Post | Authorization Policy |
php artisan make:command SendReports | Артизан-команда |
| Команда | Что делает |
|---|---|
php artisan migrate | Применить новые миграции |
php artisan migrate:rollback | Откатить последнюю партию |
php artisan migrate:fresh --seed | Drop all → migrate → seed (dev only!) |
php artisan db:seed | Запустить DatabaseSeeder |
php artisan db:seed --class=PostSeeder | Один сидер |
php artisan db:wipe | Удалить ВСЕ таблицы (опасно) |
| Команда | Что делает |
|---|---|
php artisan route:list | Все маршруты с middleware и actions |
php artisan route:list --name=user | Фильтр по имени |
php artisan tinker | REPL — интерактивно дергать модели/код |
php artisan about | Версии, окружение, кэши |
php artisan config:show database | Просмотр конфига секции |
| Команда | Что делает |
|---|---|
php artisan queue:work | Воркер очереди (foreground) |
php artisan queue:listen | Воркер, перезагружается при изменениях кода |
php artisan queue:retry all | Перезапустить failed jobs |
php artisan schedule:work | Локальный планировщик (вместо cron) |
| Команда | Когда |
|---|---|
php artisan config:cache | На проде — кэш конфигов |
php artisan route:cache | На проде — кэш маршрутов |
php artisan view:cache | Прекомпилировать Blade |
php artisan optimize | Все кэши разом |
php artisan optimize:clear | Сбросить все кэши (после изменений) |
php artisan tinker
>>> User::count();
>>> User::factory()->count(10)->create();
>>> User::where('email', 'me@x.com')->first()->delete();
Сжатый эталон для быстрого вспоминания. Скопируй в Tinker для проверки.
request('field');
$request->input('name', 'default');
$request->filled('email');
$request->has('promo');
$request->only(['email', 'name']);
$request->except(['_token', 'password']);
old('email');
$request->validate([
'email' => 'required|email|unique:users,email',
'password' => 'required|confirmed|min:8',
'role' => ['required', Rule::in(['admin', 'editor', 'user'])],
'start_date' => 'required|date',
'end_date' => 'required|date|after:start_date',
'tags' => 'array',
'tags.*' => 'string|distinct',
'profile' => 'sometimes|json',
'avatar' => 'image|mimes:jpg,png|max:2048',
]);
User::all();
User::find(1);
User::findOrFail(1);
User::where('status', 'active')->get();
User::whereIn('id', [1,2,3])->get();
User::with('posts')->get();
User::whereHas('posts', fn($q) => $q->where('status', 'published'))->get();
Post::latest()->paginate(10);
User::where('email', $e)->exists();
$c = collect([1,2,3,4,5]);
$c->map(fn($n) => $n * 2);
$c->filter(fn($n) => $n % 2);
$c->sum();
$c->avg();
$c->contains(3);
$users->groupBy('role');
$users->pluck('name', 'id');
$users->sortBy('created_at');
Str::slug('Hello World!');
Str::limit($text, 100);
Str::contains($email, '@gmail.com');
Str::random(32);
Str::uuid();
Arr::get($data, 'user.profile.email');
Arr::only($data, ['id', 'name']);
Arr::except($data, ['password']);
Arr::set($data, 'a.b.c', 1);
Arr::flatten([['a','b'],['c']]);
now();
today();
now()->addDays(7);
now()->format('d/m/Y H:i');
now()->diffForHumans();
Carbon::parse('2026-12-31')->format('l, d M Y');
session(['cart' => 3]);
session('cart', 0);
session()->flash('msg', 'Saved!');
auth()->user();
auth()->check();
auth()->id();
bcrypt('secret');
route('posts.show', ['post' => 5]);
url('/contact');
asset('css/app.css');
return redirect()->route('home');
return back()->with('error', 'Invalid');
return response()->json(['ok' => true]);
dd($user);
dump($data);
abort(403, 'Forbidden');
abort_if(!$ok, 403);
config('app.name');
env('APP_ENV');
cache('key', 'default');
tap(User::create($d), fn($u) => $u->notify());
# Generation
php artisan make:model Post -mfsc
php artisan make:controller PostController --resource
php artisan make:request StorePostRequest
php artisan make:policy PostPolicy --model=Post
# Database
php artisan migrate
php artisan migrate:fresh --seed
php artisan db:seed
# Diagnostics
php artisan route:list
php artisan tinker
php artisan about
# Production
php artisan optimize
php artisan optimize:clear
Каждый Laravel-хелпер — обёртка над стандартными PHP-функциями. Знать «внутренности» полезно на практике и когда нужно понять, почему что-то работает не так. Ниже — таблицы «Laravel → чистый PHP» для основных категорий.
| Laravel | Что делает под капотом (PHP) |
|---|---|
Str::contains($haystack, $needle) | PHP 8+: str_contains($haystack, $needle) |
Str::startsWith($str, $prefix) | PHP 8+: str_starts_with($str, $prefix) |
Str::endsWith($str, $suffix) | PHP 8+: str_ends_with($str, $suffix) |
Str::upper($str) | mb_strtoupper($str, 'UTF-8') (не strtoupper — та ломает кириллицу) |
Str::lower($str) | mb_strtolower($str, 'UTF-8') |
Str::length($str) | mb_strlen($str, 'UTF-8') |
Str::limit($str, 30) | mb_strlen($str) > 30 ? mb_substr($str, 0, 30) . '...' : $str |
Str::replace($search, $replace, $subject) | str_replace($search, $replace, $subject) |
Str::random(32) | substr(bin2hex(random_bytes(16)), 0, 32) (upgrade — base64) |
Str::slug('Привет мир!') | Транслитерация (Transliterator/iconv) → preg_replace('/[^A-Za-z0-9-]/', '-', ...) → strtolower |
Str::camel('user_name') | lcfirst(str_replace(' ', '', ucwords(str_replace(['_','-'], ' ', $str)))) |
Str::snake('userName') | strtolower(preg_replace('/(.)(?=[A-Z])/', '$1_', $str)) |
Str::kebab('userName') | Как snake, но с - вместо _ |
Str::title('hello world') | mb_convert_case($str, MB_CASE_TITLE, 'UTF-8') |
| Laravel | PHP под капотом |
|---|---|
Arr::get($arr, 'a.b.c', $default) | Рекурсия: explode('.', $key) → цикл с isset($arr[$part]) → возврат $default, если хоть где нет |
Arr::has($arr, 'a.b') | Аналогично get, но возвращает bool |
Arr::set($arr, 'a.b', $val) | explode('.') → создание вложенных массивов через & reference |
Arr::forget($arr, 'a.b') | Как set, но в конце unset() |
Arr::only($arr, ['a','b']) | array_intersect_key($arr, array_flip($keys)) |
Arr::except($arr, ['a','b']) | array_diff_key($arr, array_flip($keys)) |
Arr::pluck($arr, 'name') | array_column($arr, 'name') |
Arr::flatten($arr) | Рекурсивный foreach: если элемент массив — array_merge($result, flatten($item)) |
Arr::wrap($val) | is_array($val) ? $val : ($val === null ? [] : [$val]) |
Arr::first($arr, $callback) | foreach + if $callback($v) return $v |
Arr::random($arr) | $arr[array_rand($arr)] |
Collection — это класс-обёртка над массивом. collect([1,2,3]) = new \Illuminate\Support\Collection([1,2,3]). Каждый метод либо использует нативную функцию PHP, либо делает свой foreach.
| Laravel | PHP-эквивалент |
|---|---|
collect($arr) | new Collection($arr) — просто обёртка |
->map($fn) | array_map($fn, $arr) |
->filter($fn) | array_filter($arr, $fn) |
->reduce($fn, $init) | array_reduce($arr, $fn, $init) |
->pluck('name') | array_column($arr, 'name') |
->keys() / ->values() | array_keys($arr) / array_values($arr) |
->sum() | array_sum($arr) |
->avg() | array_sum($arr) / count($arr) |
->count() | count($arr) |
->contains($val) | in_array($val, $arr, true) или foreach + callback |
->groupBy('field') | Свой foreach: $grouped[$item[$field]][] = $item |
->sortBy('age') | usort($arr, fn($a,$b) => $a['age'] <=> $b['age']) |
->chunk(3) | array_chunk($arr, 3) |
->flatten() | Рекурсивный обход через foreach |
->toArray() | Возвращает исходный массив (для вложенных Collections — рекурсивно) |
->toJson() | json_encode($arr) |
sort() которые мутируют массив.
Carbon — обёртка над встроенным PHP-классом DateTime / DateTimeImmutable. Всё что делает Carbon — можно сделать нативно.
| Laravel | PHP-эквивалент |
|---|---|
now() | new DateTime() с timezone из config('app.timezone') |
today() | new DateTime('today') — сегодня в 00:00:00 |
$date->addDays(5) | $date->modify('+5 days') или $date->add(new DateInterval('P5D')) |
$date->subHours(2) | $date->modify('-2 hours') |
$date->format('Y-m-d') | $date->format('Y-m-d') — идентично, Carbon наследует |
Carbon::parse('2026-01-15') | new DateTime('2026-01-15') или DateTime::createFromFormat(...) |
$a->diffInDays($b) | $a->diff($b)->days |
$date->diffForHumans() | Свой алгоритм: diff() + локализация («2 часа назад») |
$date->toDateTimeString() | $date->format('Y-m-d H:i:s') |
| Laravel | PHP-эквивалент |
|---|---|
session('key') | Драйвер решает: file → $_SESSION['key'] после session_start(); redis → Redis::get("session:$id:key") |
session(['k' => $v]) | $_SESSION['k'] = $v (для file-драйвера) |
session()->flash('msg', 'ok') | $_SESSION['_flash']['msg'] = 'ok', автоочистка на след. запросе |
bcrypt($password) | password_hash($password, PASSWORD_BCRYPT, ['rounds' => 10]) |
Hash::check($pass, $hash) | password_verify($pass, $hash) |
auth()->user() | Guard → сессия/токен → User::find($id) (кешируется в память запроса) |
auth()->check() | !is_null($this->user()) |
auth()->id() | $_SESSION['login_user_web_...'] ?? null |
csrf_token() | $_SESSION['_token'] (генерируется как Str::random(40) при старте) |
| Laravel | PHP-эквивалент |
|---|---|
response('Hello', 200) | http_response_code(200); echo 'Hello'; |
response()->json($data) | header('Content-Type: application/json'); echo json_encode($data); |
response()->json($data, 422) | + http_response_code(422) |
redirect('/home') | header('Location: /home'); exit; |
redirect()->route('users.show', $id) | header('Location: ' . url_by_route_name(...)); exit; |
back() | header('Location: ' . $_SERVER['HTTP_REFERER']); exit; |
abort(404) | throw new HttpException(404) → exception handler → рендер 404-view |
abort_if($cond, 403) | if ($cond) throw new HttpException(403); |
| Laravel | PHP-эквивалент |
|---|---|
dd($var) | Обёртка: Symfony\VarDumper::dump($var); die(); (расширенный var_dump) |
dump($var) | То же, но без die() |
env('APP_KEY') | getenv('APP_KEY') ?: $_ENV['APP_KEY'] ?? $_SERVER['APP_KEY'] (через vlucas/phpdotenv) |
config('app.name') | Arr::get($configArray, 'app.name') где $configArray собран из config/*.php |
collect($arr) | new Collection($arr) |
optional($obj)->method() | PHP 8+: $obj?->method() (nullsafe operator) |
tap($val, fn($v) => $v->save()) | Вызов callback + возврат оригинала: $fn($val); return $val; |
| Laravel правило | PHP под капотом |
|---|---|
required | Значение не null, не '', не пустой массив/файл |
email | filter_var($val, FILTER_VALIDATE_EMAIL) !== false |
url | filter_var($val, FILTER_VALIDATE_URL) |
ip/ipv4/ipv6 | filter_var($val, FILTER_VALIDATE_IP) с флагами |
numeric | is_numeric($val) |
integer | filter_var($val, FILTER_VALIDATE_INT) !== false |
boolean | in_array($val, [true, false, 1, 0, '1', '0'], true) |
json | json_decode($val) !== null && json_last_error() === JSON_ERROR_NONE |
date | strtotime($val) !== false |
regex:/pattern/ | preg_match($pattern, $val) |
min:3, max:10 | Для строк — mb_strlen; для чисел — >=/<=; для массивов — count; для файлов — размер в KB |
unique:users,email | DB::table('users')->where('email', $val)->count() === 0 |
exists:categories,id | DB::table('categories')->where('id', $val)->exists() |
mimes:jpg,png | finfo_file(...) или $file->getMimeType() → сравнение |
Каждый Eloquent-метод в итоге строит SQL и выполняет через PDO.
| Laravel | SQL (примерно) | PHP (упрощённо) |
|---|---|---|
User::find(5) |
SELECT * FROM users WHERE id = 5 LIMIT 1 |
$pdo->prepare(...)->execute([5])->fetch(PDO::FETCH_ASSOC) |
User::where('active', 1)->get() |
SELECT * FROM users WHERE active = 1 |
PDO + fetchAll(PDO::FETCH_ASSOC) → hydration в объекты User |
User::pluck('email') |
SELECT email FROM users |
PDO + fetchAll(PDO::FETCH_COLUMN) |
User::whereIn('id', [1,2,3])->get() |
SELECT * FROM users WHERE id IN (?, ?, ?) |
PDO prepared с массивом плейсхолдеров |
User::paginate(10) |
2 запроса: COUNT(*) + SELECT ... LIMIT 10 OFFSET N |
2 PDO вызова + расчёт страниц |
User::with('posts')->get() |
SELECT * FROM users, потом SELECT * FROM posts WHERE user_id IN (...) — 2 запроса вместо N+1 |
PDO + hydration + подставление связей вручную по foreign_key |
User::firstOrFail() |
SELECT ... LIMIT 1 |
PDO fetch, если null — throw new ModelNotFoundException |
$user->save() |
INSERT если новый, UPDATE если существует |
PDO prepared + lastInsertId() |
$user->delete() |
DELETE FROM users WHERE id = ? |
PDO prepared execute |
User::where('active', 1)->toSql() — вернёт строку запроса. Или DB::enableQueryLog() + DB::getQueryLog() для реального выполненного SQL с параметрами.
| Laravel | PHP-эквивалент |
|---|---|
route('users.show', 5) | Поиск роута в реестре по имени + подстановка параметров в pattern → полный URL |
url('/foo') | Конкатенация: $request->getSchemeAndHttpHost() . '/foo' |
asset('css/app.css') | url() + '/css/app.css', с учётом ASSET_URL для CDN |
view('users.show', ['user' => $u]) | Blade-компилятор: .blade.php → скомпилированный PHP в storage/framework/views/*.php → include + extract($data) |
Str::slug() сработал странно — сразу ясно, что искать в Transliterator/iconv; если with() сделал 100 запросов — не сработала eager-загрузка через whereIn.