::class — это специальная константа PHP, которая возвращает полное имя класса в виде строки. Но результат зависит от того, с чем она используется — self или static.
self::class | static::class | |
|---|---|---|
| Возвращает | Имя класса, где написан код | Имя класса, на котором вызван метод |
| Учитывает наследование | Нет | Да |
| Тип связывания | Раннее (compile-time) | Позднее (runtime) |
Базовый пример
class Animal
{
public static function whoAmI(): array
{
return [
'self' => self::class,
'static' => static::class,
];
}
}
class Dog extends Animal {}
class Cat extends Animal {}
Результаты:
Animal::whoAmI();
// ['self' => 'Animal', 'static' => 'Animal']
Dog::whoAmI();
// ['self' => 'Animal', 'static' => 'Dog']
Cat::whoAmI();
// ['self' => 'Animal', 'static' => 'Cat']
self::class всегда возвращает "Animal", потому что код написан в классе Animal. А static::class подстраивается под то, какой класс вызвал метод.
Где это используется в Laravel
1. Morph-типы в Eloquent
Полиморфные связи определяют тип модели через static::class:
// Illuminate\Database\Eloquent\Model
public function getMorphClass()
{
return static::class;
}
Благодаря этому User::find(1)->getMorphClass() вернёт "App\Models\User", а не "Illuminate\Database\Eloquent\Model".
2. Имя таблицы по умолчанию
Laravel генерирует имя таблицы из имени класса модели:
public function getTable()
{
return $this->table ?? Str::snake(
Str::pluralStudly(class_basename(static::class))
);
}
User → users, BlogPost → blog_posts. Если бы здесь стоял self::class, все модели пытались бы работать с одной таблицей.
3. События модели
class User extends Model
{
protected static function booted(): void
{
static::creating(function (User $user) {
// ...
});
}
}
Здесь static::creating() привязывает событие именно к User, а не к базовому Model.
4. Фасады
// Illuminate\Support\Facades\Facade
protected static function getFacadeAccessor()
{
return static::class;
}
Каждый фасад возвращает своё имя, а не имя базового класса Facade.
Практические паттерны
Логирование с именем класса
class BaseService
{
protected function log(string $message): void
{
Log::info(static::class . ': ' . $message);
}
}
class PaymentService extends BaseService
{
public function charge(): void
{
$this->log('Начинаю списание');
// Лог: "App\Services\PaymentService: Начинаю списание"
// А не: "App\Services\BaseService: ..."
}
}
Исключения с контекстом
class BaseRepository
{
public function findOrFail(int $id): Model
{
$result = $this->find($id);
if (!$result) {
throw new ModelNotFoundException(
'Запись не найдена в ' . static::class
);
// "Запись не найдена в App\Repositories\UserRepository"
}
return $result;
}
}
Кэширование с уникальным ключом
class BaseService
{
protected function cacheKey(string $suffix): string
{
return Str::snake(class_basename(static::class)) . ':' . $suffix;
}
}
class ProductService extends BaseService
{
public function getPopular(): Collection
{
return Cache::remember(
$this->cacheKey('popular'), // "product_service:popular"
3600,
fn () => Product::popular()->get()
);
}
}
Конфигурация по конвенции
class BaseNotification extends Notification
{
public function getTemplate(): string
{
// App\Notifications\OrderShipped → "order_shipped"
$name = Str::snake(class_basename(static::class));
return "notifications.{$name}";
}
}
Когда использовать что
Используйте static::class, когда:
- Пишете базовый класс, от которого будут наследоваться другие
- Нужно знать «кто я на самом деле» — для логов, кэш-ключей, имён таблиц, morph-типов
- Работаете с паттернами фабрика, шаблонный метод, стратегия
Используйте self::class, когда:
- Нужно жёстко указать именно текущий класс, независимо от наследования
- Регистрируете класс в контейнере или конфиге и хотите указать конкретный класс
- Наследования не предполагается (финальный класс)
Связь с new static и new self
Это один и тот же механизм позднего статического связывания:
class Base
{
public static function create(): static
{
// Оба используют позднее связывание:
$className = static::class; // имя класса (строка)
$instance = new static(); // объект класса
return $instance;
}
}
Итого
self::class— всегда возвращает имя класса, где написан код.static::class— возвращает имя класса, на котором вызван метод (учитывает наследование).- В Laravel
static::classиспользуется в morph-типах, именах таблиц, событиях, фасадах. - В своём коде используйте
static::classдля логов, кэш-ключей, исключений — везде, где важно знать реальный класс.