Перейти к содержимому
Теория · Классы и объекты · урок 8 из 11

Статические члены и константы

Свойства, которые вы объявляли до сих пор, принадлежат объектам: у каждого дома своя мебель. Но иногда нужно значение, общее для всех домов сразу, например сколько домов уже построено.

Такое значение записывают прямо на чертеже. Архитектор отмечает на нём каждый новый дом, и эта отметка одна на все дома. А надпись «стены: кирпич» на чертеже не меняется никогда.

Статическое свойство

Давайте посчитаем, сколько пользователей создано:

PHP
<?php

class User
{
    public static int $count = 0;

    public function __construct(public string $name)
    {
        self::$count++;
    }
}

$anna = new User('Anna');
$boris = new User('Boris');
echo User::$count, "\n"; // 2

Разберём по шагам:

  1. public static int $count = 0; — слово static делает свойство общим для класса: ячейка одна, сколько бы объектов ни было.
  2. Внутри класса к нему обращаются через self::$count. self значит «этот класс», а знак $ у имени свойства остаётся.
  3. Каждый new — new User('Anna') и new User('Boris') — запускает конструктор, и тот прибавляет единицу к общему счётчику.
  4. Снаружи свойство читают через имя класса, и User::$count печатает 2.

Статическое свойство — свойство, которое принадлежит классу, а не объекту: оно одно на все объекты. Конструктор срабатывает при каждом new, даже если объект никуда не сохранили: строка new User('Olga'); тоже прибавит единицу.

Константа и статический метод

Константа класса — это надпись на чертеже, которая не меняется. А статический метод — вопрос, который можно задать самому чертежу, не заходя ни в один дом:

PHP
<?php

class Password
{
    const MIN_LENGTH = 8;

    public static function isStrong(string $s): bool
    {
        return strlen($s) >= self::MIN_LENGTH;
    }
}

var_dump(Password::isStrong('qwerty')); // bool(false)
echo Password::MIN_LENGTH, "\n"; // 8
echo Password::class, "\n"; // Password

Константа класса — значение, которое задают при объявлении класса и которое нельзя изменить. Статический метод — метод, который вызывают на классе, без объекта. Давайте разберём:

  1. const MIN_LENGTH = 8; объявляет константу. Знака $ у неё нет, а имя пишут заглавными буквами.
  2. Password::isStrong('qwerty') вызывает статический метод без всякого объекта.
  3. Внутри класса константу читают через self::MIN_LENGTH, снаружи — через Password::MIN_LENGTH.
  4. Password::class даёт имя класса строкой, 'Password'.

Ещё пять фактов о константах и статических методах:

  • в константе может лежать не только число, но и строка или массив: const ROLE = 'member';;
  • константе нельзя присвоить новое значение: строка Password::MIN_LENGTH = 6; даже не проходит разбор, и файл не запускается;
  • константу читают только через ::, а запись $this->MIN_LENGTH ищет свойство с таким именем и даёт Warning;
  • обычный метод нельзя вызвать через ::: на такой вызов PHP 8 отвечает ошибкой Non-static method … cannot be called statically;
  • вместо self:: иногда пишут static::, и разница между ними появляется, только когда один класс построен на основе другого.

Здесь картинка с чертежом неточна. Надписи на настоящем чертеже правит только архитектор, а static-свойство может изменить любая строка программы, которой оно доступно. Поэтому изменяемые статические свойства используют редко: за общим значением трудно уследить.

На собеседовании спрашивают: «Чем статический метод отличается от обычного?» Ответ:

  • статический метод принадлежит классу и вызывается как Password::isStrong(), без объекта, поэтому $this у него нет;
  • обычный метод вызывают на объекте, и $this в нём — этот объект.

Второй частый вопрос: когда брать константу, а когда статическое свойство. Константа нужна для значения, которое никогда не меняется, а статическое свойство — для общего изменяемого значения всего класса.

Частая ошибка

В статическом методе обращаются к $this:

PHP
<?php

class Greeter
{
    public string $name = 'Anna';

    public static function hello(): string
    {
        return 'Hi, ' . $this->name; // ✗
    }
}

echo Greeter::hello(), "\n";
TEXT
Fatal error: Uncaught Error: Using $this when not in object context

Статический метод вызвали на классе, объекта нет, поэтому нет и $this. Исправление — убрать слово static и вызвать метод на объекте: $greeter = new Greeter();, затем echo $greeter->hello();.

Главное

  • Статическое свойство одно на весь класс: внутри его читают через self::$count, снаружи — через User::$count.
  • Константа класса задаётся один раз, читается через self::NAME или User::NAME, и переприсвоить её нельзя.
  • Статический метод вызывают на классе, без объекта, и $this в нём нет.
  • User::class даёт имя класса строкой.