Экспортер
СОДЕРЖАНИЕ
- ИМЯ
- СИНТАКСИС
- ОПИСАНИЕ
- Расширенные возможности
- Рекомендации по использованию
- СМОТРИТЕ ТАКЖЕ
- ЛИЦЕНЗИЯ
ИМЯ
Exporter — Реализует метод импорта по умолчанию для модулей
СИНТАКСИС
В модуле YourModule.pm:
package YourModule;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(munge frobnicate); # symbols to export on request или
package YourModule;
use Exporter 'import'; # gives you Exporter's import() method directly
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_OK всё, но используйте @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 } , чтобы увидеть, как обрабатываются спецификации и что фактически импортируется в модули.
Экспорт без использования метода импорта Exporter
Exporter имеет специальный метод 'export_to_level', который используется в ситуациях, когда вы не можете напрямую вызвать метод импорта 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 полагается на метод импорта для работы через наследование, как есть, 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
Включив Exporter в свой @ISA вы наследуете метод импорта Exporter::import(), но вы также наследуете несколько других вспомогательных методов, которых вы, вероятно, не хотите. Чтобы этого избежать, можно сделать следующее:
package YourModule;
use Exporter qw(import); Это экспортирует собственный метод импорта Exporter::import() в 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); Если обратная совместимость с Perl ниже 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;
our (@ISA, @EXPORT_OK);
BEGIN {
require Exporter;
@ISA = qw(Exporter);
@EXPORT_OK = qw(munge frobnicate); # symbols to export on request
} BEGIN гарантирует, что загрузка Exporter.pm и присвоения @ISA и @EXPORT_OK произойдут немедленно, не оставляя места для того, чтобы что-то пошло не так или просто неправильно.
Что касается загрузки Exporter и наследования, есть альтернативы с использованием модулей, таких как base и parent.
use base qw(Exporter);
# or
use parent qw(Exporter); Любое из этих утверждений является хорошим замещением для BEGIN { require Exporter; @ISA = qw(Exporter); } с тем же эффектом времени компиляции. Основное различие заключается в том, что код base взаимодействует с объявленными fields переменными, в то время как parent представляет собой усовершенствованную версию старого кода base для простого установления отношения "является".
Для получения более подробной информации см. документацию и код 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.34.0/Exporter