Spec-Zone.ru › Perl 5.38

Экспортер

СОДЕРЖАНИЕ

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

НАЗВАНИЕ

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;

Это импортирует все символы из @EXPORT в пространство имён оператора 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 обрабатывает число версии как простое числовое значение, он будет считать версию 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.

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

Хорошие Практики

Объявление @EXPORT_OK и Друзей

При использовании Exporter со стандартными strict и warnings препроцессорами, необходимо использовать ключевое слово 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;

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–2023 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.38.0/Exporter

Spec-Zone.ru

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