Так что я действительно озадачен анонимными функциями в PHP, я хочу знать, используются ли анонимные функции в основном по вкусу или стилю кодирования.
Я спрашиваю об этом, потому что вы можете достичь того же результата без функции обратного вызова и меньшего количества кода.
Итак, вот некоторый тестовый код:
$output = 10;
$people = (new People(new John));
//VERSION 1 ANONYMOUS FUNCTION
$people->run(function ($value) use(&$output){
$output = $output + $value;
});
var_dump($output); //RESULT => 20
//VERSION 2 WITHOUT ANONYMOUS FUNCTION
var_dump($people->run() + $output); //RESULT => 30
Вы можете запустить и увидеть полный код здесь:
https://www.tehplayground.com/IhWJJU0jbNnzuird
<?php
interface HumanInterface
{
public function hello();
}
class People
{
protected $person;
protected $value;
public function __construct(HumanInterface $person)
{
$this->person = $person;
return $this;
}
public function run(callable $callback = null, $name = null)
{
$this->value = 10;
if(is_callable($callback)) {
return call_user_func($callback, $this->value);
}
return $this->value;
}
}
class John implements HumanInterface
{
public function hello()
{
return 'hi i am john';
}
}
$output = 10;
$people = (new People(new John));
$people->run(function ($value) use(&$output){
$output = $output + $value;
});
var_dump($output);
var_dump($people->run() + $output);
Поэтому мой вопрос: зачем использовать анонимную функцию? Это вопрос
личный выбор?
Анонимные функции или «замыкания» очень полезны, если они используются в качестве одноразового обратного вызова. Если вы используете PHP usort
метод например. Вторым параметром может быть Закрытие. Поэтому вместо написания именованной функции, которая используется один раз, а затем никогда больше, вы используете Closure.
ИМХО, это единственный способ использовать замыкания: как обратный вызов.
Анонимные функции полезны для последующего выполнения или для других функций, принимающих код. Их использование может значительно сократить код, необходимый для выполнения каких-либо задач.
Представь, что у тебя есть UserCollection
объект, который использует общую коллекцию внизу. Вы хотите уменьшить UserCollection
только пользователям из определенной страны. Чтобы вы могли добавить метод findByCountry()
на UserCollection
:
public function findByCountry($country) : UserCollection {
$subset = new UserCollection;
foreach ($this->users as $user) {
if ($user->country === $country) {
$subset->add($user);
}
}
return $subset;
}
Это все хорошо, но дополнительные методы поиска будут делать то же самое: выполнять итерации и собирать в подмножество только с разными критериями. Так много шаблонного кода.
Вы можете легко отделить шаблон от критериев, добавив метод find(callable $callback)
в основной коллекции, вот так:
public function find(callable $criteria) : Collection {
$subset = new Collection;
foreach ($this->users as $user) {
if ($criteria($user)) {
$subset->add($user);
}
}
return $subset;
}
Это общий поиск. Теперь ваш код в UserCollection
будет содержать только фактические критерии:
public function findByCountry($country): UserCollection {
return $this->subset(function(User $user) {
return $user->country === $country;
});
}
private function subset($criteria): UserCollection {
return new UserCollection($this->allUsers->find($criteria));
}
Отделяя критерии от стандартного, гораздо проще понять, что вы пытаетесь найти пользователей по стране. Там нет итерационного кода, отвлекающего от фактических критериев. Так становится легче понять и меньше усилий писать. Кроме того, вы не можете случайно испортить итерацию, потому что она определена в другом месте.
При использовании анонимных функций, подобных этой, они очень похожи на использование шаблона стратегии или FilterIterator
, Заметная разница в том, что вы создаете их на лету.
Обратите внимание, что вы должны различать лямбды и затворы. Я сознательно проигнорировал разницу для этого ответа.