Что такое закрытие PHP7?

Вот код, это простой контейнер.

class Application
{
  private $recipes;
  private $instances;

  public function configureCache(XXXXXXXX $closure) {
    $recipes['cache'] = $closure;
  }

  public function getCache(): Cache {
    if (empty($instances['cache'])) {
      $instances['cache'] = $recipes['cache']();
    }
    return $instances['cache'];
  }
}

Этот код работает на PHP 7.1+. Что я могу заполнить для XXXXXXXX, чтобы сделать его наиболее конкретным? Тип - это функция, а точнее функция, возвращающая кэш.

это оно? php.net/manual/en/class.closure.php

Isaac 31.05.2018 00:08

что насчет php.net/manual/en/language.types.callable.php

Isaac 31.05.2018 00:08

Не уверен на 100%, поэтому я не публикую его в качестве ответа, но я думаю, что правильный тип подсказки в этом случае является "вызываемым", если вы хотите, чтобы он мог принимать анонимные функции.

rickdenhaan 31.05.2018 00:09

Связанный: stackoverflow.com/q/29730720/1941241

rickdenhaan 31.05.2018 00:11

Используйте get_class и введите подсказку к тому, что он возвращает ...?

ficuscr 31.05.2018 00:12

Также стоит отметить, что, несмотря на то, что PHP называет класс «Closure», PHP не имеет фактических закрытий, как можно было бы ожидать от других языков, в той области, в которой он объявлен, нет импортирован в анонимную функцию или иным образом не стал доступным для нее.

Sammitch 31.05.2018 00:43

@Sammitch Я бы немного изменил это: в PHP импорт области всегда явный, поэтому при закрытии явно необходимо импортировать переменные, которые они хотят использовать, с предложением use. Переменные, импортированные с помощью use, действуют точно так же, как и ожидалось, что сработает закрытие, и могут быть захвачены по значению или ссылке по усмотрению пользователя.

IMSoP 31.05.2018 11:14
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
2
7
958
2

Ответы 2

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

Подсказка типа для всего этого - callable.

Если вам нужны только анонимные функции, то есть закрытие первого класса, используйте Closure. Но это ограничило бы виды вызываемых, которые вы могли принять.

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

Я думаю, что мне действительно нужно, чтобы функции PHP были перенесены на Swift.

William Entriken 31.05.2018 00:18

Если вы специально хотите заставить кого-то передать анонимную функцию, то это всегда будет экземпляр класс Closure.

Если вам действительно нужно «что-то, что вы можете использовать как функцию», вы можете использовать вызываемый псевдотип, который принимает как замыкания, так и различные нотации строк и массивов для ссылок на именованные функции и методы.

Вы также можете преобразовать любой вызываемый объект в экземпляр Closure, используя Закрытие :: fromCallable.

К сожалению, вы не можете получить более конкретную информацию; были предложения по указанию конкретных сигнатур для вызываемых объектов или разрешению им соответствовать специально созданным определениям интерфейсов, но пока ни одно из них не было принято.

Однако вам может потребоваться объект, реализующий нормальный интерфейс с одним методом, и я считаю, что этот метод может быть волшебный метод __invoke. Затем вызывающий может использовать анонимный класс вместо анонимной функции:

interface CacheFactory {
    public function __invoke(): Cache;
} 
$app->configureCache(new class implements CacheFactory {
    public function __invoke(): Cache {
          return new Cache;
    }
});

Обратите внимание, что полученный объект сам будет передавать подсказку типа callable, а также CacheFactory, и его можно использовать так же, как анонимную функцию в вашем примере.

Однако даже с этим решением проверяется только тип во время выполнения, поэтому этот код сам по себе не вызовет никаких ошибок, и вы просто получите ошибку типа в 10% случаев когда вы действительно запускаете обратный вызов:

$app->configureCache(new class implements CacheFactory {
    public function __invoke(): Cache {
          return rand(0,10) > 9 ? "Nonsense" : new Cache;
    }
});

В большинстве случаев вам, вероятно, просто нужен callable и хорошая документация.

Другие вопросы по теме