Avatar ·

Когда в PHP использовать self, а когда $this? Разница и примеры

Всем привет! Я начал изучать ООП в PHP и никак не могу понять разницу между `self` и `$this`. Вроде бы оба используются внутри класса для доступа к свойствам и методам, но постоянно путаюсь. Вот пример моего кода: ```php class User { public $name = 'Гость'; public static $count = 0; public function setName($name) { $this->name = $name; // почему не self? } public static function getCount() { return self::$count; // почему не $this? } } ``` Когда я пишу `$this->name` — всё работает. Но если я пишу `self::$name` — вылезает ошибка. А со статическим свойством наоборот: `self::$count` работает, а `$this->count` — нет. Я читал мануал, но там слишком сложно. Объясните простыми словами: когда нужно использовать `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() не передаёт контекст объекта.