Когда использовать self, а когда $this? Разбираемся раз и навсегда
Если вы когда-нибудь писали на PHP в объектно-ориентированном стиле, то наверняка сталкивались с вопросом: «А что, собственно, выбрать — self или $this?». Этот вопрос настолько популярен, что на Stack Overflow он собрал десятки тысяч просмотров и сотни комментариев. И это не случайно: разница между ними — одна из тех «мелочей», которая может превратить ваш код в работающий, но неочевидный, или в элегантный и понятный.
Давайте сразу договоримся: это не взаимозаменяемые вещи. У них разная философия и, что важнее, разное поведение при наследовании. Если вы используете $this там, где нужно self, или наоборот — вы рискуете получить логические ошибки, которые сложно отловить.
В этой статье мы разложим всё по полочкам: от базы до продвинутых сценариев. Поехали!
Короткий ответ (для тех, кто спешит)
Если вы хотите запомнить только одно правило, запомните это:
$this->— для обращения к свойствам и методам экземпляра (объекта). Работает только внутри нестатического контекста.self::— для обращения к статическим свойствам и методам класса. Работает как в статическом, так и в нестатическом контексте.static::— «позднее статическое связывание» (Late Static Binding). Используется, когда нужно, чтобы дочерний класс переопределил поведение родителя.
Но дьявол, как всегда, кроется в деталях. Давайте углубимся.
Что такое $this?
$this — это псевдопеременная, которая ссылается на текущий объект. Она доступна только внутри методов класса (не статических) и указывает на тот самый экземпляр, с которым вы работаете.
<?php
class User {
public string $name;
public function setName(string $name): void {
$this->name = $name; // обращаемся к свойству текущего объекта
}
public function getName(): string {
return $this->name;
}
}
$user = new User();
$user->setName('Анна');
echo $user->getName(); // Анна
Всё просто: $this->name — это «возьми свойство name у того самого объекта, который вызвал этот метод».
Что такое self?
self — это ссылка на текущий класс, а не на объект. Он используется для доступа к статическим членам класса (свойствам и методам, объявленным с ключевым словом static).
<?php
class Config {
public static string $appName = 'PythonLib';
public static function getAppName(): string {
return self::$appName; // обращаемся к статическому свойству класса
}
}
echo Config::getAppName(); // PythonLib
Обратите внимание: self всегда ссылается на тот класс, в котором он написан. Даже если вы создадите наследника, self в родительском классе продолжит указывать на родителя. Это важнейшее отличие от static.
Главное отличие: self vs $this при наследовании
Вот здесь начинается самое интересное. Представьте, что у вас есть базовый класс Animal и дочерний класс Dog.
<?php
class Animal {
public static function whoAmI(): string {
return 'Я — животное';
}
public function say(): string {
// Используем self — он привязан к классу Animal
return self::whoAmI();
}
}
class Dog extends Animal {
public static function whoAmI(): string {
return 'Я — собака';
}
}
$dog = new Dog();
echo $dog->say(); // Я — животное
Удивились? Метод say() вызван у объекта класса Dog, но self::whoAmI() внутри него всё равно вызвал метод класса Animal. Почему? Потому что self резолвится на этапе компиляции, а не выполнения. Он «зашит» в тот класс, где написан.
Если же мы хотим, чтобы при вызове метода say() у собаки вызывался именно её метод whoAmI(), нужно использовать static:
<?php
class Animal {
public static function whoAmI(): string {
return 'Я — животное';
}
public function say(): string {
// Используем static — он будет резолвиться во время выполнения
return static::whoAmI();
}
}
class Dog extends Animal {
public static function whoAmI(): string {
return 'Я — собака';
}
}
$dog = new Dog();
echo $dog->say(); // Я — собака
Это и есть позднее статическое связывание (Late Static Binding), появившееся в PHP 5.3. Оно позволяет «унаследовать» статический контекст.
Когда использовать $this?
Используйте $this, когда:
- Вы обращаетесь к нестатическим свойствам объекта (
$this->name,$this->age). - Вы вызываете нестатические методы того же объекта (
$this->calculate()). - Вы находитесь внутри нестатического метода и хотите передать текущий объект в другой метод (
$this->sendEmail($this)).
Главное правило: $this — это про конкретный экземпляр.
Когда использовать self?
Используйте self, когда:
- Вы обращаетесь к статическим свойствам класса (
self::$counter). - Вы вызываете статические методы того же класса (
self::validate()). - Вы находитесь внутри статического метода —
$thisтам вообще недоступен. - Вы хотите явно указать, что метод или свойство принадлежат именно этому классу, а не наследнику (чтобы избежать неожиданного переопределения).
Когда использовать static?
static:: — это ваш выбор, когда:
- Вы пишете код в родительском классе и хотите, чтобы дочерние классы могли его переопределить.
- Вы используете паттерн Factory Method или Singleton с наследованием.
- Вы работаете с трейтами и хотите, чтобы метод трейта вызывал переопределённый метод в классе, который использует трейт.
<?php
trait