Spec-Zone.ru › Perl 5.32

Exporter

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • СИНОПСИС
  • ОПИСАНИЕ
    • Как экспортировать
    • Выбор того, что экспортировать
    • Как импортировать
  • Расширенные возможности
    • Специализированные списки импорта
    • Экспорт без использования метода import Exporter
    • Экспорт без наследования от Exporter
    • Проверка версии модуля
    • Управление неизвестными символами
    • Утилитарные функции обработки тегов
    • Генерация объединённых тегов
    • Константы AUTOLOAD
  • Рекомендации по использованию
    • Объявление @EXPORT_OK и связанных функций
    • Безопасность
    • Что не следует экспортировать
  • СМОТРИТЕ ТАКЖЕ
  • ЛИЦЕНЗИЯ

НАЗВАНИЕ

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 из-за высокой гибкости интерфейса и оптимизации реализации для распространённых случаев.

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;

Это импортирует все символы из @EXPORT YourModule в пространство имён оператора 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

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

Включив Exporter в ваш @ISA вы наследуете метод import() Exporter, но также наследуете и другие вспомогательные методы, которые вам, вероятно, не нужны. Чтобы этого избежать, вы можете сделать так:

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" для упрощения инструкций "использования".

Самый простой способ сделать это:

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.

Если вы пишете пакет, который AUTOLOADs, рассмотрите возможность принудительного AUTOLOAD для любых констант, явно импортированных другими пакетами или обычно используемых, когда ваш пакет used.

Рекомендации по практике

Объявление @EXPORT_OK и др.

При использовании Exporter со стандартными strict и warnings прагмами требуется ключевое слово 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. Таким образом, первая часть кода в "ПРИМЕРЫ" может быть переписана как:

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 для установления только отношения "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–2020 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.32.0/Exporter

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API