Вот код, это простой контейнер.
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/language.types.callable.php
Не уверен на 100%, поэтому я не публикую его в качестве ответа, но я думаю, что правильный тип подсказки в этом случае является "вызываемым", если вы хотите, чтобы он мог принимать анонимные функции.
Связанный: stackoverflow.com/q/29730720/1941241
Используйте get_class и введите подсказку к тому, что он возвращает ...?
Также стоит отметить, что, несмотря на то, что PHP называет класс «Closure», PHP не имеет фактических закрытий, как можно было бы ожидать от других языков, в той области, в которой он объявлен, нет импортирован в анонимную функцию или иным образом не стал доступным для нее.
@Sammitch Я бы немного изменил это: в PHP импорт области всегда явный, поэтому при закрытии явно необходимо импортировать переменные, которые они хотят использовать, с предложением use. Переменные, импортированные с помощью use, действуют точно так же, как и ожидалось, что сработает закрытие, и могут быть захвачены по значению или ссылке по усмотрению пользователя.






PHP поддерживает несколько синтаксисов для вызываемых сущностей: строка, содержащая имя функции, массив объекта и метода, массив класса и метода в случае статических методов, замыкания первого класса и сгенерированные замыкания.
Подсказка типа для всего этого - callable.
Если вам нужны только анонимные функции, то есть закрытие первого класса, используйте Closure. Но это ограничило бы виды вызываемых, которые вы могли принять.
На данный момент PHP не поддерживает подсказки аргументов или подсказки типа возвращаемого значения для формальных вызываемых аргументов: например, ваш код не может сказать, принимать только замыкания, которые принимают один строковый параметр и возвращают логическое значение.
Я думаю, что мне действительно нужно, чтобы функции PHP были перенесены на Swift.
Если вы специально хотите заставить кого-то передать анонимную функцию, то это всегда будет экземпляр класс 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 и хорошая документация.
это оно? php.net/manual/en/class.closure.php