Что такое тип закрытия 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, чтобы сделать его наиболее конкретным? Тип — это функция, а точнее функция, которая возвращает кэш.


person William Entriken    schedule 30.05.2018    source источник
comment
это оно? php.net/manual/en/class.closure.php   -  person Isaac    schedule 31.05.2018
comment
Не уверен на 100%, поэтому я не публикую его как ответ, но я думаю, что подсказку правильного типа в этом случае можно вызвать, если вы хотите, чтобы он мог принимать анонимные функции.   -  person rickdenhaan    schedule 31.05.2018
comment
Связано: stackoverflow.com/q/29730720/1941241   -  person rickdenhaan    schedule 31.05.2018
comment
Используйте get_class и введите намек на то, что он возвращает...?   -  person ficuscr    schedule 31.05.2018
comment
Также стоит отметить, что, несмотря на то, что PHP называет класс Closure, PHP не имеет фактических замыканий, как можно было бы ожидать от других языков, в той области, в которой он объявлен, он не импортируется или иным образом не доступен для , анонимная функция.   -  person Sammitch    schedule 31.05.2018
comment
@Sammitch Я бы немного изменил это: в PHP импорт области всегда является явным, поэтому закрытия должны явно импортировать переменные, которые они хотят использовать, с предложением use. Переменные, импортированные с помощью use, действуют точно так же, как вы ожидаете от закрытия, и могут быть захвачены по значению или ссылке по усмотрению пользователя.   -  person IMSoP    schedule 31.05.2018


Ответы (2)


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

Подсказка типа для всех них — callable.

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

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

person bishop    schedule 30.05.2018
comment
Я предполагаю, что я действительно хочу, чтобы функции PHP были перенесены на Swift. - person William Entriken; 31.05.2018

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

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

Вы также можете преобразовать любой callable в экземпляр 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 и хорошую документацию.

person IMSoP    schedule 30.05.2018