PHP OOP: понимание статических методов
Статические методы PHP: определение и вызов, self:: vs static:: (позднее статическое связывание), счётчики, фабричные методы и подводные камни.
Статический метод — это метод, объявленный с ключевым словом static, который принадлежит самому классу, а не какому-либо конкретному объекту, созданному из него. Поскольку он привязан к классу, его можно вызывать напрямую через имя класса и оператор разрешения области видимости (::) — без new.
В этой главе показано, как определять и вызывать статические методы, чем они отличаются от обычных (экземплярных) методов, как ведут себя self:: и static:: внутри них, а также паттерны, где статические методы действительно полезны (утилиты, счётчики и фабричные методы). Если вы только знакомитесь с классами, сначала прочитайте Классы и объекты PHP.
Что такое статические методы в PHP?
Обычные методы работают с конкретным объектом и могут обращаться к его данным через $this. Статический метод не имеет $this — он не привязан ни к какому экземпляру, поэтому может работать только с переданными аргументами и с собственными статическими членами класса.
Это делает статические методы естественным выбором для операций без состояния: вычислений, зависящих только от входных данных, а не от состояния конкретного объекта. Классический пример — вычисление среднего значения списка чисел.
class Math
{
public static function average(array $numbers): float
{
return array_sum($numbers) / count($numbers);
}
}Зачем использовать статические методы?
| Причина | Что это означает на практике |
|---|---|
| Отсутствие состояния | Результат зависит только от аргументов, поэтому он предсказуем и легко тестируем. |
| Без создания экземпляра | Вы пропускаете new ClassName() — удобно для вспомогательных/утилитных функций. |
| Общее состояние | Статические методы могут читать и обновлять статические свойства, позволяя классу отслеживать данные для всех его объектов (например, счётчик). |
| Фабричные методы | Статический метод может создать и вернуть настроенный экземпляр, давая более понятную альтернативу сложному конструктору. |
Компромисс: поскольку статические методы нельзя переопределить через обычную ссылку на объект и они не несут состояния экземпляра, их избыточное использование затрудняет создание моков и модульное тестирование. Предпочитайте методы экземпляра, когда поведение зависит от состояния объекта.
Как определить и вызвать статический метод
Добавьте static перед именем метода, затем вызовите его через ClassName::method():
<?php
class Math
{
public static function average(array $numbers): float
{
return array_sum($numbers) / count($numbers);
}
}
$average = Math::average([1, 2, 3, 4, 5]);
echo $average; // 3Токен :: — это оператор разрешения области видимости — тот же оператор, который используется для констант класса.
self:: vs static:: и отсутствие $this
Внутри статического метода нельзя использовать $this, потому что нет экземпляра, на который можно сослаться. Чтобы обратиться к другому статическому члену класса, используйте self:: или static::.
self::разрешается к классу, в котором написан метод.static::использует позднее статическое связывание — оно разрешается к классу, который был вызван во время выполнения, что важно при наследовании.
<?php
class Base
{
public static function create(): string
{
return self::class; // always "Base"
}
public static function make(): string
{
return static::class; // the called class
}
}
class Child extends Base {}
echo Base::create(), "\n"; // Base
echo Child::create(), "\n"; // Base (self:: is fixed to where it's written)
echo Child::make(), "\n"; // Child (static:: follows the call)Используйте static::, когда родительский класс определяет поведение, которое подклассы должны уметь перенаправить на себя — это основа фабричного паттерна, описанного ниже. Подробнее в Наследовании PHP.
Статические методы со статическими свойствами: счётчик
Статические методы часто используются совместно со статическими свойствами для хранения состояния, разделяемого между всеми объектами класса.
<?php
class User
{
public static int $count = 0;
public function __construct(public string $name)
{
self::$count++;
}
public static function total(): int
{
return self::$count;
}
}
new User('Ada');
new User('Linus');
echo User::total(); // 2Обратите внимание: total() читает self::$count без объекта — свойство хранится в классе, а не в конкретном User.
Фабричные методы
Статический метод, возвращающий новый экземпляр, называется фабричным методом. Он предоставляет именованный и читаемый способ создания объектов:
<?php
class Temperature
{
private function __construct(private float $celsius) {}
public static function fromCelsius(float $c): static
{
return new static($c);
}
public static function fromFahrenheit(float $f): static
{
return new static(($f - 32) * 5 / 9);
}
public function celsius(): float
{
return $this->celsius;
}
}
$t = Temperature::fromFahrenheit(212);
echo $t->celsius(); // 100Использование new static() (позднее статическое связывание) означает, что подкласс, вызывающий fromCelsius(), получит экземпляр себя, а не Temperature.
Частые подводные камни
$thisнедоступен. Его использование внутри статического метода вызывает фатальную ошибку — нет текущего объекта.- Статические и экземплярные методы могут иметь одинаковое имя только в разных классах, но не в одном. Внутри класса каждое имя метода уникально.
- Статический метод можно вызвать на объекте (
$obj::method()или даже$obj->method()), но он всё равно выполнится без$this. Вызов через$obj->допустим, но вводит в заблуждение — предпочитайтеClassName::method()для ясности. - Статическое состояние глобально для процесса. Статический счётчик разделяется между всеми экземплярами и сохраняется на протяжении всего запроса, что может удивить в длительно работающем или тестовом коде.
Заключение
Статические методы принадлежат классу, выполняются без экземпляра и не имеют доступа к $this. Они хорошо подходят для утилит без состояния, общего состояния класса через статические свойства и фабричных методов для создания настроенных объектов. Используйте self::, когда имеете в виду определяющий класс, и static::, когда подклассы должны уметь перенаправить вызов на себя. Выбирайте статические методы, когда поведение привязано к классу, а не к конкретному объекту — и предпочитайте методы экземпляра в противном случае.
Далее углубите понимание с помощью Статических свойств PHP и Констант класса PHP.