Laravel предоставляет богатый набор вспомогательных функций (helpers) и систему контрактов (interfaces), определяющих основные сервисы фреймворка. Понимание их различий критически важно для сертификации.
Хелперы массивов (Arr)
Класс Illuminate\Support\Arr предоставляет удобные методы для работы с массивами:
use Illuminate\Support\Arr;
// Arr::get() - Get value using dot notation
$data = ['user' => ['name' => 'John', 'address' => ['city' => 'Moscow']]];
Arr::get($data, 'user.name'); // 'John'
Arr::get($data, 'user.address.city'); // 'Moscow'
Arr::get($data, 'user.phone', 'N/A'); // 'N/A' (default)
// Arr::has() - Check if key exists
Arr::has($data, 'user.name'); // true
Arr::has($data, 'user.phone'); // false
Arr::has($data, ['user.name', 'user.address']); // true (all keys exist)
// Arr::set() - Set value using dot notation
Arr::set($data, 'user.phone', '+7999');
// $data['user']['phone'] = '+7999'
// Arr::dot() - Flatten multidimensional array to dot notation
$flat = Arr::dot($data);
// ['user.name' => 'John', 'user.address.city' => 'Moscow']
// Arr::undot() - Expand dot notation back
$expanded = Arr::undot($flat);
// ['user' => ['name' => 'John', 'address' => ['city' => 'Moscow']]]
// Arr::only() - Return only specified keys
$filtered = Arr::only($data['user'], ['name', 'address']);
// Arr::except() - Return all except specified keys
$filtered = Arr::except($data['user'], ['address']);
// Arr::first() / Arr::last()
$first = Arr::first([1, 2, 3, 4], fn ($value) => $value > 2);
// 3
$last = Arr::last([1, 2, 3, 4], fn ($value) => $value < 3);
// 2
// Arr::flatten() - Flatten multidimensional array
$nested = ['name' => 'John', 'languages' => ['PHP', 'JS']];
$flat = Arr::flatten($nested);
// ['John', 'PHP', 'JS']
// Arr::pluck()
$users = [
['name' => 'John', 'email' => '[email protected]'],
['name' => 'Jane', 'email' => '[email protected]'],
];
Arr::pluck($users, 'email');
// ['[email protected]', '[email protected]']
Arr::pluck($users, 'email', 'name');
// ['John' => '[email protected]', 'Jane' => '[email protected]']
// Arr::where() - Filter array by callback
$filtered = Arr::where([1, 2, 3, 4, 5], fn ($value) => $value > 3);
// [3 => 4, 4 => 5]
// Arr::shuffle() - Randomly shuffle
$shuffled = Arr::shuffle([1, 2, 3, 4, 5]);
// Arr::random() - Get random element(s)
$random = Arr::random([1, 2, 3, 4, 5]); // One random element
$randoms = Arr::random([1, 2, 3, 4, 5], 2); // Two random elements
// Arr::wrap() - Wrap value in array
Arr::wrap('hello'); // ['hello']
Arr::wrap(['hello']); // ['hello'] (already array)
Arr::wrap(null); // []
// Arr::pull() - Get value and remove from array
$array = ['name' => 'John', 'age' => 30];
$name = Arr::pull($array, 'name');
// $name = 'John', $array = ['age' => 30]
// Arr::exists() - Check if key exists (even if value is null)
Arr::exists(['key' => null], 'key'); // true
// Arr::map()
$mapped = Arr::map([1, 2, 3], fn ($value) => $value * 2);
// [2, 4, 6]
Хелперы строк (Str)
use Illuminate\Support\Str;
// Case transformations
Str::camel('hello_world'); // 'helloWorld'
Str::studly('hello_world'); // 'HelloWorld'
Str::snake('helloWorld'); // 'hello_world'
Str::kebab('helloWorld'); // 'hello-world'
Str::title('hello world'); // 'Hello World'
Str::headline('helloWorld'); // 'Hello World'
Str::lower('HELLO'); // 'hello'
Str::upper('hello'); // 'HELLO'
Str::ucfirst('hello world'); // 'Hello world'
// String checks
Str::contains('Hello World', 'World'); // true
Str::contains('Hello World', ['Foo', 'World']); // true (any)
Str::containsAll('Hello World', ['Hello', 'World']); // true
Str::startsWith('Hello', 'He'); // true
Str::endsWith('Hello', 'lo'); // true
Str::is('foo*', 'foobar'); // true (pattern matching)
// String manipulation
Str::slug('Laravel Framework'); // 'laravel-framework'
Str::slug('Laravel Framework', '_'); // 'laravel_framework'
Str::limit('Long text here', 10); // 'Long text...'
Str::limit('Long text here', 10, '>>>'); // 'Long text>>>'
Str::words('This is a long sentence', 3); // 'This is a...'
Str::plural('car'); // 'cars'
Str::singular('cars'); // 'car'
Str::substr('Hello World', 6); // 'World'
Str::before('Hello World', ' '); // 'Hello'
Str::after('Hello World', ' '); // 'World'
Str::between('[Hello]', '[', ']'); // 'Hello'
Str::replace('World', 'Laravel', 'Hello World'); // 'Hello Laravel'
Str::replaceFirst('foo', 'bar', 'foo foo foo'); // 'bar foo foo'
Str::replaceLast('foo', 'bar', 'foo foo foo'); // 'foo foo bar'
Str::remove('World', 'Hello World'); // 'Hello '
Str::trim(' Hello '); // 'Hello'
Str::squish('Hello World '); // 'Hello World'
Str::padLeft('1', 5, '0'); // '00001'
Str::padRight('1', 5, '0'); // '10000'
Str::mask('1234567890', '*', 4); // '1234******'
Str::mask('1234567890', '*', 4, 4); // '1234****90'
Str::repeat('ha', 3); // 'hahaha'
Str::reverse('Hello'); // 'olleH'
// IDs and random
Str::uuid(); // UUID v4
Str::orderedUuid(); // Time-ordered UUID
Str::ulid(); // ULID
Str::random(32); // Random alphanumeric string
Str::password(16); // Random password
// Length
Str::length('Hello'); // 5
Str::wordCount('Hello World'); // 2
// Wrap and Finish
Str::wrap('value', '"'); // '"value"'
Str::finish('path/', '/'); // 'path/' (adds / if not present)
Str::start('/path', '/'); // '/path' (adds / if not present)
Fluent Strings (Stringable)
use Illuminate\Support\Str;
// Fluent chainable API
$result = Str::of('Hello World')
->lower()
->replace('world', 'laravel')
->slug()
->toString();
// 'hello-laravel'
// Complex example
$cleanedTitle = Str::of($request->title)
->trim()
->squish()
->limit(100)
->title()
->toString();
// With conditional operations
$filename = Str::of($file->getClientOriginalName())
->beforeLast('.')
->slug()
->append('-', now()->format('Y-m-d'))
->append('.', $file->extension())
->toString();
// 'my-document-2026-02-22.pdf'
// Fluent string checks
$result = Str::of('[email protected]')
->contains('@'); // true
// When/Unless
$greeting = Str::of('Hello')
->when($user->isPremium(), fn ($s) => $s->append(' Premium'))
->append(' User')
->toString();
// 'Hello Premium User' or 'Hello User'
data_get(), data_set(), data_fill()
Эти хелперы работают с вложенными структурами данных через точечную нотацию и поддерживают wildcards:
// data_get() - Get nested value with dot notation
$data = [
'orders' => [
['id' => 1, 'items' => [['name' => 'Laptop', 'price' => 999]]],
['id' => 2, 'items' => [['name' => 'Mouse', 'price' => 49]]],
],
];
data_get($data, 'orders.0.id'); // 1
data_get($data, 'orders.0.items.0.name'); // 'Laptop'
data_get($data, 'orders.missing', 'N/A'); // 'N/A' (default)
// Wildcard - get from all elements
data_get($data, 'orders.*.id');
// [1, 2]
data_get($data, 'orders.*.items.*.name');
// [['Laptop'], ['Mouse']]
// data_set() - Set nested value
data_set($data, 'orders.0.status', 'shipped');
data_set($data, 'orders.*.status', 'processing'); // Set all
// data_fill() - Set only if not already set
data_fill($data, 'orders.0.status', 'pending');
// Won't overwrite if 'status' already exists
// data_forget() - Remove nested key
data_forget($data, 'orders.0.items');
::alert{type="warning"}
Для экзамена: data_get() поддерживает wildcards (*). Arr::get() не поддерживает wildcards. Если нужен wildcard-доступ к вложенным данным, используйте data_get().
::
rescue()
Выполняет callback и возвращает значение по умолчанию при ошибке:
// Basic usage - returns default on exception
$value = rescue(fn () => $this->riskyOperation(), 'fallback');
// With closure as default
$value = rescue(
fn () => ExternalApi::getData(),
fn () => cache()->get('cached_data', []),
);
// Report exception (true by default)
$value = rescue(fn () => $this->parse($input), 'error', report: true);
// Don't report exception
$value = rescue(fn () => json_decode($json, true), [], report: false);
retry()
Повторяет callback указанное число раз при ошибке:
// Retry 3 times with 100ms delay
$result = retry(3, function (int $attempt) {
return ExternalApi::call();
}, sleepMilliseconds: 100);
// Retry with custom delay per attempt
$result = retry(5, function (int $attempt) {
return Http::get('https://api.example.com/data')->json();
}, sleepMilliseconds: fn (int $attempt) => $attempt * 200);
// Retry only on specific exceptions
$result = retry(3, function () {
return DB::transaction(function () {
// ...
});
}, sleepMilliseconds: 100, when: fn (\Exception $e) => $e instanceof DeadlockException);
throw_if() и throw_unless()
// Throw if condition is true
throw_if(
$order->isPaid(),
new OrderAlreadyPaidException('Order is already paid.'),
);
// Throw with simple string (creates RuntimeException)
throw_if(empty($data), 'Data cannot be empty.');
// Throw with class
throw_if(!$user->canAccess(), AuthorizationException::class, 'Access denied.');
// throw_unless - throw if condition is false
throw_unless(auth()->check(), AuthenticationException::class);
throw_unless(
$user->hasPermission('edit'),
AuthorizationException::class,
'You do not have permission to edit.'
);
Другие важные хелперы
blank() и filled()
// blank() - true for "empty" values
blank(''); // true
blank(' '); // true
blank(null); // true
blank(collect()); // true
blank([]); // true
blank(0); // false (!)
blank('0'); // false (!)
blank(false); // false (!)
// filled() - inverse of blank()
filled('hello'); // true
filled(0); // true
filled(false); // true
filled(''); // false
filled(null); // false
::alert{type="warning"}
Внимание: blank() отличается от PHP empty(). blank(0) возвращает false, empty(0) возвращает true. blank() считает 0, '0', false как "filled" (заполненные) значения.
::
value() и with()
// value() - resolve value (execute if closure)
$value = value('hello'); // 'hello'
$value = value(fn () => 'hello'); // 'hello'
// Useful in config/defaults
$default = value($config['callback'] ?? 'fallback');
// with() - return value after applying callback
$result = with('Hello', fn ($value) => strtoupper($value));
// 'HELLO'
optional()
// Safely access properties/methods on potentially null objects
$name = optional($user)->name; // null if $user is null
$email = optional($user)->getEmail(); // null if $user is null
// With callback
$result = optional($user, fn ($u) => $u->getFullName());
// null if $user is null, otherwise calls getFullName()
once()
// Execute callback only once, cache result
$value = once(fn () => expensiveCalculation());
$value = once(fn () => expensiveCalculation()); // Returns cached result
// Useful in classes
final class ReportService
{
public function getStats(): array
{
return once(fn () => [
'users' => User::count(),
'orders' => Order::count(),
'revenue' => Order::sum('total'),
]);
}
}
today(), now()
$today = today(); // Carbon instance for today (midnight)
$now = now(); // Carbon instance for now
$now = now('UTC'); // Now in UTC timezone
transform()
// Transform value if not blank
$result = transform('hello', fn ($value) => strtoupper($value));
// 'HELLO'
$result = transform('', fn ($value) => strtoupper($value));
// '' (returned as-is because blank)
$result = transform(null, fn ($value) => strtoupper($value), 'default');
// 'default'
Контракты (Contracts)
Контракты - это набор интерфейсов, определяющих основные сервисы Laravel. Они находятся в пакете illuminate/contracts.
Зачем нужны контракты
// Using Facade (implementation)
use Illuminate\Support\Facades\Cache;
Cache::get('key');
// Using Contract (interface)
use Illuminate\Contracts\Cache\Repository;
public function __construct(
private readonly Repository $cache,
) {}
$this->cache->get('key');
Ключевые контракты
// Authentication
Illuminate\Contracts\Auth\Guard
Illuminate\Contracts\Auth\Factory // Auth manager
Illuminate\Contracts\Auth\Authenticatable // User model interface
// Cache
Illuminate\Contracts\Cache\Repository // Cache store
Illuminate\Contracts\Cache\Factory // Cache manager
// Queue
Illuminate\Contracts\Queue\Queue
Illuminate\Contracts\Queue\ShouldQueue // Queue marker
// Mail
Illuminate\Contracts\Mail\Mailer
Illuminate\Contracts\Mail\Mailable
// Filesystem
Illuminate\Contracts\Filesystem\Filesystem
Illuminate\Contracts\Filesystem\Cloud
// Events
Illuminate\Contracts\Events\Dispatcher
// Database
Illuminate\Contracts\Database\Eloquent\Builder
// Container
Illuminate\Contracts\Container\Container
Illuminate\Contracts\Foundation\Application
Контракты vs Фасады
| Аспект | Контракты (Interfaces) | Фасады (Facades) |
|---|---|---|
| Тип | PHP интерфейс | Статический прокси |
| DI | Через конструктор | Не требуется |
| Тестирование | Легко мокать | Встроенные fakes |
| IDE поддержка | Полная из коробки | Нужен плагин/пакет |
| Связанность | Слабая (зависимость от интерфейса) | Сильная (зависимость от фасада) |
// Contract approach (recommended for services/libraries)
declare(strict_types=1);
namespace App\Services;
use Illuminate\Contracts\Cache\Repository as CacheContract;
use Illuminate\Contracts\Events\Dispatcher;
final class ProductService
{
public function __construct(
private readonly CacheContract $cache,
private readonly Dispatcher $events,
) {}
public function getProduct(int $id): Product
{
return $this->cache->remember(
"product:{$id}",
3600,
fn () => Product::findOrFail($id)
);
}
}
// Facade approach (common in controllers/routes)
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
Route::get('/product/{id}', function (int $id) {
return Cache::remember("product:{$id}", 3600, fn () => Product::findOrFail($id));
});
Когда использовать что
Используйте контракты (интерфейсы) когда:
- Разрабатываете пакет/библиотеку
- Нужна слабая связанность
- Планируете замену реализации
- В сервисных классах и репозиториях
Используйте фасады когда:
- В контроллерах и маршрутах
- В одноразовых скриптах
- В тестах (встроенные fake-методы)
- Когда DI не приносит пользы
// Auto-resolving contracts from container
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Contracts\Cache\Repository;
final class DashboardController extends Controller
{
// Laravel auto-resolves the contract to the configured implementation
public function index(Repository $cache): View
{
$stats = $cache->remember('dashboard:stats', 300, fn () => [
'users' => User::count(),
'orders' => Order::count(),
]);
return view('dashboard', compact('stats'));
}
}
Хелперы путей
// Application paths
app_path('Models/User.php'); // /app/Models/User.php
base_path('vendor'); // /vendor
config_path('app.php'); // /config/app.php
database_path('migrations'); // /database/migrations
public_path('css/app.css'); // /public/css/app.css
resource_path('views'); // /resources/views
storage_path('logs/laravel.log'); // /storage/logs/laravel.log
lang_path('en/messages.php'); // /lang/en/messages.php
Хелперы конфигурации и окружения
// config()
$value = config('app.name'); // Get value
$value = config('app.name', 'Default'); // With default
config(['app.name' => 'New Name']); // Set at runtime
// env() - ONLY use in config files!
$debug = env('APP_DEBUG', false);
// app()
$app = app(); // Application instance
$service = app(UserService::class); // Resolve from container
$env = app()->environment(); // Current environment
$isProduction = app()->isProduction();