Динамическое создание и вызов функций — один из самых гибких механизмов Perl, унаследованный из традиций латекса и shell-скриптов. Ещё с ранних версий Perl допускает вызов функций по строке (через символические ссылки/globs), хранение ссылок на подпрограммы в переменных и ассоциативных массивах, а также конструкцию AUTOLOAD для генерации функций на лету.
Главная проблема такого подхода — безопасность (возможность вызова нежелательной функции по подставной строке) и производительность (символическое разрешение имён медленнее прямого вызова). Также важен контроль за областью видимости функций и передачей правильного числа аргументов.
Решение — использовать хэш-диспетчер (mapping from string/keyword to coderef), избегать eval для запуска кода пользователя, чётко определять перечень разрешённых к вызову функций.
Пример кода (диспетчеризация по ключу):
my %dispatch = ( add => sub { $_[0] + $_[1] }, sub => sub { $_[0] - $_[1] }, mult => sub { $_[0] * $_[1] }, ); my $key = 'add'; if (exists $dispatch{$key}) { print $dispatch{$key}->(2, 3); # Выведет 5 } else { die "Unknown action $key"; }
Ключевые особенности:
Можно ли вызвать функцию по её имени, используя только строку?
Ответ: Да, но это опасно — вызов $fn_name->() или через прямую символическую ссылку &$fn_name(); не рекомендуется с внешними (пользовательскими) данными, так как это приводит к потенциальным уязвимостям.
Есть ли разница между кодовой ссылкой и именем функции в Perl?
Ответ: Да, имя функции всегда глобально, а ссылка на функцию (coderef) может быть лексической, локальной, передаваться между подпрограммами и хранить анонимную функцию.
my $coderef = sub { ... }; my $named = \&fn_name;
Что происходит, если вызвать несуществующую функцию через хэш-диспетчер?
Ответ: Если ключа нет — возникнет ошибка. Поэтому всегда требуется проверка exists перед вызовом и обработка нераспознанных команд, иначе будет попытка вызвать undef (фатальная ошибка).
Команда на сайте принимает имя функции из GET-параметра и вызывает через eval — любой пользователь может вызвать system, unlink и прочие опасные функции.
Плюсы:
Минусы:
Используется хэш с белым списком функций, все показатели валидируются, eval не используется, ошибки перехватываются и логируются.
Плюсы:
Минусы: