Ответ
Магический метод __invoke() позволяет экземпляру объекта быть вызванным как функцию. Когда объект используется с синтаксисом вызова функции $object(), PHP автоматически вызывает его метод __invoke().
Основные сценарии использования:
- Объекты-функции (функторы): Создание объектов, которые хранят состояние между вызовами, в отличие от обычных функций.
- Callback-и с состоянием: Удобная передача в функции вроде
array_map,usort, где нужна не просто статическая логика, а конфигурируемое поведение. - Альтернатива замыканиям (closures) для сложной логики, которую удобно инкапсулировать в класс.
Практический пример — стратегия с состоянием:
class DiscountCalculator {
private $discountRate;
public function __construct(float $discountRate) {
$this->discountRate = $discountRate;
}
public function __invoke(float $price): float {
return $price * (1 - $this->discountRate);
}
}
// Создаем стратегии с разным состоянием (процентом скидки)
$regularDiscount = new DiscountCalculator(0.1); // 10%
$vipDiscount = new DiscountCalculator(0.25); // 25%
$prices = [100.0, 200.0, 300.0];
// Применяем разные стратегии как функции
$regularPrices = array_map($regularDiscount, $prices);
$vipPrices = array_map($vipDiscount, $prices);
print_r($regularPrices); // [90, 180, 270]
print_r($vipPrices); // [75, 150, 225]
Метод __invoke() стирает грань между объектами и функциями, позволяя использовать преимущества ООП (инкапсуляция, состояние) в контекстах, рассчитанных на функции.
Ответ 18+ 🔞
Смотри, есть в PHP такая прикольная штука — __invoke(). Если по-простому, она позволяет твоему объекту прикинуться функцией. Ну то есть ты пишешь $object(), а PHP, вместо того чтобы охуеть и выдать ошибку, тихонько вызывает этот самый __invoke().
Зачем это вообще нужно, спросишь ты?
- Объекты-функции (или функторы, если хочешь умничать). Представь, тебе нужна функция, но с памятью. Обычная функция — она как золотая рыбка, хуй вспомнит, что было в прошлый раз. А объект с
__invoke()— это уже слон, он своё состояние между вызовами хранит. - Callback-и с мозгом. Когда тебе нужно в
array_mapилиusortзапихнуть не просто анонимку, а что-то посерьёзнее, с настройками внутри. - Иногда проще, чем замыкание. Если логика такая, что её в класс удобнее завернуть, а не в
function() use (...) {...}.
Пример из жизни, чтобы совсем понятно стало: Допустим, у нас калькулятор скидок. Но скидки-то разные бывают!
class DiscountCalculator {
private $discountRate; // Вот наше состояние, наша память
public function __construct(float $discountRate) {
$this->discountRate = $discountRate;
}
// А это волшебство! Теперь объект можно вызывать как функцию.
public function __invoke(float $price): float {
return $price * (1 - $this->discountRate);
}
}
// Создаём две стратегии. Одна для обычных покупателей, другая для VIP.
$regularDiscount = new DiscountCalculator(0.1); // 10% скидка
$vipDiscount = new DiscountCalculator(0.25); // 25% скидки, ядрёна вошь!
$prices = [100.0, 200.0, 300.0];
// И теперь просто кидаем эти объекты в array_map, как будто это обычные функции!
$regularPrices = array_map($regularDiscount, $prices);
$vipPrices = array_map($vipDiscount, $prices);
print_r($regularPrices); // [90, 180, 270]
print_r($vipPrices); // [75, 150, 225] — вот это уже выгодно, ёпта!
Короче, __invoke() — это такой мостик. С одной стороны — объект со всеми его плюшками (состояние, инкапсуляция), а с другой — ведёт себя как простая функция, куда его ни сунь. Довольно хитрая жопа, если вдуматься.