Экспортер
СОДЕРЖАНИЕ
ИМЯ
Exporter — Реализует метод импорта по умолчанию для модулей
СИНОПСИС
В модуле YourModule.pm:
package YourModule;
use Exporter 'import';
our @EXPORT_OK = qw(munge frobnicate); # symbols to export on request или
package YourModule;
require Exporter;
our @ISA = qw(Exporter); # inherit all of Exporter's methods
our @EXPORT_OK = qw(munge frobnicate); # symbols to export on request или
package YourModule;
use parent 'Exporter'; # inherit all of Exporter's methods
our @EXPORT_OK = qw(munge frobnicate); # symbols to export on request В других файлах, которые хотят использовать YourModule:
use YourModule qw(frobnicate); # import listed symbols
frobnicate ($left, $right) # calls YourModule::frobnicate Посмотрите в "Рекомендации по практике" для некоторых вариантов, которые вы захотите использовать в современном коде Perl.
ОПИСАНИЕ
Модуль Exporter реализует метод import , который позволяет модулю экспортировать функции и переменные в пространства имен своих пользователей. Многие модули используют Exporter вместо реализации собственного метода import , потому что Exporter предоставляет высоко гибкий интерфейс, с реализацией, оптимизированной для общего случая.
Perl автоматически вызывает метод import при обработке оператора use для модуля. Модули и use документированы в perlfunc и perlmod. Понимание концепции модулей и того, как работает оператор use , важно для понимания Exporter.
Как экспортировать
Массивы @EXPORT и @EXPORT_OK в модуле содержат списки символов, которые будут по умолчанию экспортироваться в пространство имен пользователей, или которые они могут запросить для экспорта соответственно. Символы могут представлять функции, скаляры, массивы, хеши или типы глобальных переменных. Символы должны быть указаны полным именем, за исключением того, что амперсанд перед функцией является необязательным, например:
our @EXPORT = qw(afunc $scalar @array); # afunc is a function
our @EXPORT_OK = qw(&bfunc %hash *typeglob); # explicit prefix on &bfunc Если вы экспортируете только имена функций, рекомендуется опустить амперсанд, так как реализация в этом случае быстрее.
Выбор того, что экспортировать
Не экспортируйте имена методов!
Не экспортируйте ничего по умолчанию без веской причины!
Экспорт загрязняет пространство имен пользователя модуля. Если вы должны экспортировать, попытайтесь использовать @EXPORT_OK вместо @EXPORT и избегайте коротких или общих имён символов, чтобы уменьшить риск конфликтов имён.
В общем, всё, что не экспортировано, по-прежнему доступно извне модуля с помощью синтаксиса YourModule::item_name (или $blessed_ref->method). По соглашению, вы можете использовать ведущую подчёркивание в именах, чтобы неофициально указать, что они являются «внутренними» и не предназначены для публичного использования.
(На самом деле, можно получить приватные функции, сказав:
my $subref = sub { ... };
$subref->(@args); # Call it as a function
$obj->$subref(@args); # Use it as a method Однако, если вы используете их для методов, вам придётся разобраться, как заставить наследование работать.)
Как общее правило, если модуль пытается быть объектно-ориентированным, то не экспортируйте ничего. Если это просто набор функций, то экспортируйте только то, что необходимо, но используйте @EXPORT с осторожностью. Для имён функций и методов используйте слова без префиксов в списках экспорта, а не имена с префиксом амперсанда.
Дополнительные рекомендации по проектированию модулей можно найти в perlmod.
Как импортировать
В других файлах, которые хотят использовать ваш модуль, есть три основных способа загрузить ваш модуль и импортировать его символы:
-
use YourModule; -
Это импортирует все символы из
@EXPORTYourModule в пространство имен оператораuse. -
use YourModule (); -
Это заставляет perl загрузить ваш модуль, но не импортирует никакие символы.
-
use YourModule qw(...); -
Это импортирует только символы, перечисленные вызывающей стороной, в их пространство имён. Все перечисленные символы должны быть в вашем
@EXPORTили@EXPORT_OK, иначе произойдёт ошибка. К расширенным функциям экспорта Exporter можно получить доступ таким же образом, но со вхождениями списка, которые синтаксически отличаются от имён символов.
Если вам не нужны расширенные возможности, этого, вероятно, достаточно, чтобы использовать Exporter.
Расширенные возможности
Специализированные списки импорта
Если какое-либо из вхождений в списке импорта начинается с !, : или /, то список обрабатывается как серия спецификаций, которые либо добавляют, либо удаляют из списка импортируемых имён. Они обрабатываются слева направо. Спецификации имеют вид:
[!]name This name only
[!]:DEFAULT All names in @EXPORT
[!]:tag All names in $EXPORT_TAGS{tag} anonymous array
[!]/pattern/ All names in @EXPORT and @EXPORT_OK which match Ведущий ! указывает, что соответствующие имена должны быть удалены из списка импортируемых имён. Если первая спецификация является удалением, она обрабатывается так, как будто перед ней стоит :DEFAULT. Если вы просто хотите импортировать дополнительные имена в дополнение к набору по умолчанию, вам всё равно нужно явно включить :DEFAULT.
Например, Module.pm определяет:
our @EXPORT = qw(A1 A2 A3 A4 A5);
our @EXPORT_OK = qw(B1 B2 B3 B4 B5);
our %EXPORT_TAGS = (T1 => [qw(A1 A2 B1 B2)], T2 => [qw(A1 A2 B3 B4)]); Обратите внимание, что вы не можете использовать теги в @EXPORT или @EXPORT_OK.
Имена в EXPORT_TAGS также должны присутствовать в @EXPORT или @EXPORT_OK.
Приложение, использующее Module, может сказать что-то вроде:
use Module qw(:DEFAULT :T2 !B3 A3); Другие примеры включают:
use Socket qw(!/^[AP]F_/ !SOMAXCONN !SOL_SOCKET);
use POSIX qw(:errno_h :termios_h !TCSADRAIN !/^EXIT/); Помните, что большинство шаблонов (с использованием //) необходимо будет закрепить с ведущим ^, например, /^EXIT/ вместо /EXIT/.
Вы можете сказать BEGIN { $Exporter::Verbose=1 } , чтобы увидеть, как обрабатываются спецификации и что фактически импортируется в модули.
Экспорт без использования метода import экспортера
Exporter имеет специальный метод 'export_to_level', который используется в ситуациях, когда вы не можете напрямую вызвать метод import Exporter. Метод export_to_level выглядит следующим образом:
MyPackage->export_to_level(
$where_to_export, $package, @what_to_export
); где $where_to_export — целое число, указывающее, насколько далеко вверх по стеку вызовов нужно экспортировать ваши символы, а @what_to_export — массив, указывающий, какие символы *экспортировать* (обычно это @_). Аргумент $package в настоящее время не используется.
Например, предположим, что у вас есть модуль A, у которого уже есть функция импорта:
package A;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw($b);
sub import
{
$A::b = 1; # not a very useful import method
} и вы хотите экспортировать символ $A::b обратно в модуль, который использовал пакет A. Поскольку Exporter полагается на метод import для работы через наследование, как есть, Exporter::import() никогда не будет вызван. Вместо этого сделайте следующее:
package A;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw($b);
sub import
{
$A::b = 1;
A->export_to_level(1, @_);
} Это экспортирует символы на уровень «выше» текущего пакета — то есть, в программу или модуль, который использовал пакет A.
Примечание: Будьте осторожны, чтобы не изменять @_ вообще до вызова export_to_level — иначе пользователи вашего пакета получат очень необъяснимые результаты!
Экспорт без наследования от экспортера
Включив Exporter в свой @ISA , вы наследуете метод import() экспортера, но также наследуете несколько других вспомогательных методов, которых, вероятно, не нужно и которые усложняют дерево наследования. Чтобы этого избежать, вы можете сделать:
package YourModule;
use Exporter qw(import); что экспортирует собственный метод import() Exporter в YourModule. Всё будет работать как раньше, но вам не нужно включать Exporter в @YourModule::ISA.
Примечание: Эта функция была добавлена в версии 5.57 Exporter, выпущенной с Perl 5.8.3.
Проверка версии модуля
Модуль Exporter преобразует попытку импорта числа из модуля в вызов $module_name->VERSION($value). Это можно использовать для проверки того, что версия используемого модуля больше или равна требуемой версии.
По историческим причинам, Exporter предоставляет метод require_version , который просто делегирует VERSION. Первоначально, до существования UNIVERSAL::VERSION, Exporter вызывал require_version.
Поскольку метод UNIVERSAL::VERSION рассматривает число $VERSION как простое числовое значение, он будет считать версию 1.10 меньше, чем 1.9. По этой причине настоятельно рекомендуется использовать числа как минимум с двумя десятичными знаками, например, 1.09.
Управление неизвестными символами
В некоторых ситуациях вы можете захотеть предотвратить экспорт определённых символов. Как правило, это относится к расширениям, которые имеют функции или константы, которые могут отсутствовать на некоторых системах.
Имена всех символов, которые нельзя экспортировать, должны быть перечислены в массиве @EXPORT_FAIL.
Если модуль пытается импортировать любой из этих символов, Exporter даст модулю возможность обработать ситуацию до генерации ошибки. Exporter вызовет метод export_fail со списком проваленных символов:
@failed_symbols = $module_name->export_fail(@failed_symbols); Если метод export_fail возвращает пустой список, то ошибка не регистрируется, и все запрошенные символы экспортируются. Если возвращённый список не пустой, то для каждого символа генерируется ошибка, и экспорт завершается неудачей. Exporter предоставляет метод export_fail по умолчанию, который просто возвращает список без изменений.
Использование метода export_fail включает предоставление более информативных сообщений об ошибках для некоторых символов и выполнение ленивых архитектурных проверок (поместите больше символов в @EXPORT_FAIL по умолчанию, а затем удалите их, если кто-то действительно попытается их использовать, и дорогая проверка покажет, что они применимы на этой платформе).
Утилитарные функции обработки тегов
Поскольку символы, перечисленные в %EXPORT_TAGS , должны также присутствовать в @EXPORT или @EXPORT_OK, предоставляются две утилитарные функции, которые позволяют легко добавлять помеченные наборы символов в @EXPORT или @EXPORT_OK:
our %EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]);
Exporter::export_tags('foo'); # add aa, bb and cc to @EXPORT
Exporter::export_ok_tags('bar'); # add aa, cc and dd to @EXPORT_OK Любые имена, которые не являются тегами, добавляются к @EXPORT или @EXPORT_OK без изменений, но это вызовет предупреждение (с -w), чтобы избежать того, что неверно написанные имена тегов будут безмолвно добавлены к @EXPORT или @EXPORT_OK. В будущих версиях это может стать фатальной ошибкой.
Генерация комбинированных тегов
Если в %EXPORT_TAGS существуют несколько категорий символов, обычно полезно создать утилиту ":all", чтобы упростить операторы "use".
Самый простой способ сделать это:
our %EXPORT_TAGS = (foo => [qw(aa bb cc)], bar => [qw(aa cc dd)]);
# add all the other ":class" tags to the ":all" class,
# deleting duplicates
{
my %seen;
push @{$EXPORT_TAGS{all}},
grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}} foreach keys %EXPORT_TAGS;
} CGI.pm создаёт тег ":all", который содержит некоторые (но не все) категории. Это можно сделать с небольшим изменением:
# add some of the other ":class" tags to the ":all" class,
# deleting duplicates
{
my %seen;
push @{$EXPORT_TAGS{all}},
grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}}
foreach qw/html2 html3 netscape form cgi internal/;
} Обратите внимание, что имена тегов в %EXPORT_TAGS не содержат ведущего ':'.
AUTOLOADые константы
Многие модули используют AUTOLOAD для подпрограмм констант, чтобы избежать компиляции и потерь памяти на редко используемых значениях (см. perlsub для получения информации о подпрограммах констант). Вызовы таких подпрограмм констант не оптимизируются во время компиляции, потому что их неизменность нельзя проверить на этапе компиляции.
Даже если прототип доступен во время компиляции, тело подпрограммы нет (ещё не AUTOLOADо). perl должен проверить как прототип (), так и тело подпрограммы во время компиляции, чтобы определить, может ли он безопасно заменить вызовы этой подпрограммы значением константы.
Обходным путём является вызов констант в блоке BEGIN:
package My ;
use Socket ;
foo( SO_LINGER ); ## SO_LINGER NOT optimized away; called at runtime
BEGIN { SO_LINGER }
foo( SO_LINGER ); ## SO_LINGER optimized away at compile time. Это заставляет AUTOLOAD для SO_LINGER произойти до того, как SO_LINGER будет встречен позже в пакете My.
Если вы пишете пакет, который AUTOLOADет, рассмотрите возможность принудительного AUTOLOAD для любых констант, явно импортированных другими пакетами или которые обычно используются, когда ваш пакет useен.
Рекомендации по практикам
Объявление @EXPORT_OK и друзей
При использовании Exporter со стандартными strict и warnings пragmaми, необходимо ключевое слово our, чтобы объявить переменные пакета @EXPORT_OK, @EXPORT, @ISA, и т. д.
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(munge frobnicate); Если обратная совместимость с Perls ниже 5.6 важна, необходимо написать вместо этого оператор use vars.
use vars qw(@ISA @EXPORT_OK);
@ISA = qw(Exporter);
@EXPORT_OK = qw(munge frobnicate); Безопасные действия
Существуют некоторые оговорки относительно использования операторов времени выполнения, таких как require Exporter и присвоения переменных пакетам, которые могут быть очень тонкими для неопытного программиста. Это может произойти, например, с взаимно рекурсивными модулями, которые зависят от времени выполнения соответствующих конструкций.
Идеальный способ никогда не думать об этом – использовать блоки BEGIN и простой метод импорта. Таким образом, первая часть кода "SYNOPSIS" может быть переписана как:
package YourModule;
use strict;
use warnings;
use Exporter 'import';
BEGIN {
our @EXPORT_OK = qw(munge frobnicate); # symbols to export on request
} Или, если вам нужно унаследовать от Exporter:
package YourModule;
use strict;
use warnings;
BEGIN {
require Exporter;
our @ISA = qw(Exporter); # inherit all of Exporter's methods
our @EXPORT_OK = qw(munge frobnicate); # symbols to export on request
} BEGIN гарантирует, что загрузка Exporter.pm и присвоения @ISA и @EXPORT_OK произойдут немедленно, как и use, не оставляя места для сбоев или ошибок.
В отношении загрузки Exporter и наследования существуют альтернативы с использованием модулей, таких как base и parent.
use base qw(Exporter);
# or
use parent qw(Exporter); Любое из этих утверждений является хорошей заменой для BEGIN { require Exporter; our @ISA = qw(Exporter); }, с тем же эффектом на этапе компиляции. Основное различие заключается в том, что код base взаимодействует с объявленными fields, а parent – это оптимизированная версия старого кода base для установления отношения IS-A.
Для более подробной информации см. документацию и код модулей base и parent.
Ещё одним надёжным средством решения проблемы времени выполнения и компиляции является использование Exporter::Easy, который является оболочкой Exporter, позволяющей объединить весь вспомогательный код в одном операторе use.
use Exporter::Easy (
OK => [ qw(munge frobnicate) ],
);
# @ISA setup is automatic
# all assignments happen at compile time Что не следует экспортировать
В разделе "Выбор того, что экспортировать" вам уже было сказано не экспортировать:
-
имена методов (потому что вам это не нужно, и это, вероятно, не даст желаемого результата),
-
ничего по умолчанию (потому что вы не хотите удивлять своих пользователей... серьёзно),
-
ничего, что вам не нужно (потому что меньше – это больше).
В этот список следует добавить ещё один пункт. Не экспортируйте имена переменных. Просто потому, что Exporter позволяет это сделать, не значит, что вы должны.
@EXPORT_OK = qw($svar @avar %hvar); # DON'T! Экспорт переменных – не хорошая идея. Они могут меняться под капотом, вызывая ужасные побочные эффекты, которые слишком трудно отследить и исправить. Поверьте мне: они того не стоят.
Для обеспечения возможности установки/получения настроек класса лучше вместо этого предоставить методы доступа в виде подпрограмм или методов класса.
См. также
Exporter определённо не единственный модуль с возможностями экспорта символов. На CPAN вы можете найти множество таких модулей. Некоторые из них легче. Некоторые предоставляют улучшенные API и функции. Выберите тот, который соответствует вашим потребностям. Ниже приведён примерный список таких модулей.
Exporter::Easy
Exporter::Lite
Exporter::Renaming
Exporter::Tidy
Sub::Exporter / Sub::Installer
Perl6::Export / Perl6::Export::Attrs ЛИЦЕНЗИЯ
Эта библиотека – свободное программное обеспечение. Вы можете перераспределять и/или изменять её на тех же условиях, что и сам Perl.
© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/Exporter