Звичайний метод працює з конкретним об'єктом і має доступ до $this - його стану.
Статичний метод належить класу, а не об'єкту: викликається без створення екземпляра (Money::fromCents(100)), і $this у ньому немає.
final class Money
{
private function __construct(private int $cents) {}
public static function fromCents(int $cents): self // статичний: створює об'єкт
{
return new self($cents);
}
public function add(Money $other): self // звичайний: працює зі станом
{
return new self($this->cents + $other->cents);
}
}
Коли static доречний:
- Іменовані конструктори й фабричні методи:
Money::fromCents(),Carbon::parse(). - Чисті допоміжні функції без стану, логічно прив'язані до класу:
Str::slug(). - Константи й кеш на рівні класу - обережно (див. нижче).
Чому зі статикою обережні:
- Важко підмінити в тестах. Код, що викликає
PaymentGateway::charge(), жорстко прив'язаний до класу; залежність, передана в конструктор, легко замінюється на фейк. - Статичні властивості - глобальний стан. Вони живуть увесь процес: у довгоживучих воркерах і Octane значення «перетікає» між запитами.
- Приховані залежності: зі сигнатури класу не видно, що він користується статикою іншого класу.
Фасади Laravel (Cache::get()) лише виглядають статичними: насправді це виклик методу об'єкта з контейнера, і в тестах його можна підмінити (Cache::fake(), Cache::shouldReceive()).