Когда в PHP использовать self, а когда $this? Разница и примеры
Главное отличие: self — для статического, $this — для контекста объекта
Давайте разберёмся раз и навсегда. Ключевое различие в том, к чему именно вы обращаетесь:
$this— ссылка на текущий экземпляр (объект). Используется для нестатических свойств и методов.self— ссылка на текущий класс. Используется для статических свойств, констант и статических методов.
Правило №1: $this — для конкретного объекта
$this работает только внутри нестатических методов. Он указывает на тот самый объект, который вы создали через new. У каждого объекта свои значения свойств:
class User {
public $name = 'Гость';
public function setName($name) {
$this->name = $name; // меняем свойство именно этого объекта
}
}
$user1 = new User();
$user2 = new User();
$user1->setName('Анна');
echo $user1->name; // Анна
echo $user2->name; // Гость — не изменилось!
Почему нельзя self::$name? Потому что self не знает, с каким именно объектом вы работаете. Он обращается к классу в целом, а нестатические свойства принадлежат объекту.
Правило №2: self — для статики и констант
self используется для доступа к статическим свойствам (принадлежат классу, а не объекту) и константам:
class User {
public static $count = 0;
const MAX_USERS = 100;
public static function getCount() {
return self::$count; // обращаемся к статическому свойству класса
}
public function __construct() {
self::$count++; // увеличиваем счётчик при создании объекта
}
}
$user1 = new User();
$user2 = new User();
echo User::getCount(); // 2
echo User::MAX_USERS; // 100
$this->count не сработает, потому что статические свойства не хранятся в объекте — они общие для всех экземпляров.
Подводный камень: наследование (self vs static)
Самый частый сюрприз — позднее статическое связывание. Если вы используете self в родительском классе, он всегда будет ссылаться на родительский класс, даже если метод вызван у наследника:
class ParentClass {
public static function who() {
echo __CLASS__; // ParentClass
}
public static function testSelf() {
self::who(); // всегда ParentClass
}
public static function testStatic() {
static::who(); // зависит от контекста вызова
}
}
class ChildClass extends ParentClass {
public static function who() {
echo __CLASS__; // ChildClass
}
}
ChildClass::testSelf(); // ParentClass — неожиданно?
ChildClass::testStatic(); // ChildClass — правильно!
Поэтому в наследовании для вызова переопределённых статических методов используйте static:: вместо self::.
Краткая шпаргалка
- $this->property — нестатическое свойство объекта
- $this->method() — нестатический метод объекта
- self::$property — статическое свойство класса
- self::CONSTANT — константа класса
- self::method() — статический метод класса
- static::method() — статический метод с поздним связыванием (для наследования)
Запомните простое правило: если вы работаете с данными, которые меняются от объекта к объекту — используйте $this. Если данные общие для всех объектов или это константа — используйте self.
Дополнение: когда self может обмануть в наследовании
К ответу выше добавлю важный нюанс про переопределение свойств. В PHP 8.1+ появилась поддержка асинхронных статических свойств через self, но классическая ловушка остаётся.
Рассмотрим пример, где self и $this ведут себя по-разному при наследовании нестатических методов:
class Animal {
protected $sound = '...';
public function makeSound() {
echo $this->sound; // использует свойство объекта
}
public function showClass() {
echo self::class; // всегда 'Animal'
}
}
class Dog extends Animal {
protected $sound = 'Woof!';
}
$dog = new Dog();
$dog->makeSound(); // Woof! — $this подхватил переопределённое свойство
$dog->showClass(); // Animal — self не меняется
$this всегда смотрит на реальный объект, даже если метод определён в родителе. А self привязан к классу, где написан код. Если вам нужно получить имя класса наследника внутри родительского метода, используйте static::class.
Ещё один совет: не пытайтесь использовать self для нестатических методов — это технически возможно (вызовет предупреждение в новых версиях PHP), но лишено смысла, так как self::method() не передаёт контекст объекта.
Ответов пока нет.
Войдите чтобы оставить ответ