perlmod
СОДЕРЖАНИЕ
ИМЯ
perlmod - Модули Perl (пакеты и таблицы символов)
ОПИСАНИЕ
Этот ли документ вы искали?
Существуют и другие документы, которые могут содержать искомую информацию:
- Этот документ
-
Пакеты Perl, пространства имен и некоторые сведения о классах.
- perlnewmod
-
Руководство по созданию нового модуля.
- perlmodstyle
-
Рекомендации по созданию нового модуля.
Пакеты
В отличие от Perl 4, где все переменные были динамическими и использовали одно глобальное пространство имен, что вызывало проблемы с поддержкой, Perl 5 предоставляет два механизма для защиты кода от перезаписи его переменных другим кодом: лексически ограниченные переменные, созданные с помощью my или state, и именованные глобальные переменные, доступ к которым обеспечивается с помощью vars pragma или our ключевого слова. Любая глобальная переменная считается частью пространства имен и может быть обращена через «полную форму». Напротив, любая лексически ограниченная переменная считается частью этого лексического пространства и не имеет «полной формы».
В Perl пространства имен называются «пакетами», а package объявление сообщает компилятору, какое пространство имен добавить как префикс к our переменным и неопределенным динамическим именам. Это обеспечивает защиту от случайного перезаписывания и предоставляет интерфейс для преднамеренного перезаписывания глобальных динамических переменных, объявленных и используемых в других областях или пакетах, когда это нужно.
Область действия package объявления простирается от самого объявления до конца содержащего блока, eval, или файла, что наступит раньше (такая же область действия, как у операторов my(), our(), state() и local(), а также эффект экспериментального «алиасирования ссылок», который может измениться), или до следующего package объявления. Неопределённые динамические идентификаторы будут находиться в этом пространстве имен, за исключением тех немногих идентификаторов, которые, если они не определены, по умолчанию относятся к главному пакету, а не к текущему, как описано ниже. Оператор package затрагивает только динамические глобальные символы, включая имена подпрограмм и переменные, над которыми вы использовали local(), но не лексические переменные, созданные с помощью my(), our() или state().
Обычно оператор package является первым объявлением в файле, включённом в программу одним из операторов do, require или use. Вы можете переключаться в пакет в нескольких местах: package не имеет эффекта, кроме указания таблицы символов, которую компилятор будет использовать для динамических символов до конца этого блока или до следующего package оператора. Вы можете обращаться к переменным и файловым дескрипторам в других пакетах, добавляя префикс имени пакета и двойное двоеточие: $Package::Variable. Если имя пакета пустое, подразумевается пакет main. То есть $::sail эквивалентно $main::sail.
Старым разделителем пакетов был одиночный символ кавычки, но теперь предпочтительным разделителем является двойное двоеточие, отчасти потому, что оно удобнее для чтения человеком, и отчасти потому, что оно удобнее для макросов emacs. Это также позволяет программистам на C++ лучше понимать, что происходит, в отличие от использования одинарной кавычки в качестве разделителя, что делалось для того, чтобы программисты на Ada лучше понимали, что происходит. Поскольку устаревшая синтаксическая конструкция всё ещё поддерживается для обратной совместимости, если вы попытаетесь использовать строку, такую как "This is $owner's house", вы будете обращаться к $owner::s; то есть к переменной $s в пакете owner, что, вероятно, не то, что вы имели в виду. Используйте фигурные скобки для устранения неоднозначности, как в "This is ${owner}'s house".
Пакеты могут сами содержать разделители пакетов, как в $OUTER::INNER::var. Однако это ни о чём не говорит о порядке поиска имён. Нет относительных пакетов: все символы либо локальны для текущего пакета, либо должны быть полностью квалифицированы от имени внешнего пакета вниз. Например, внутри пакета OUTER нигде $INNER::var не ссылается на $OUTER::INNER::var. INNER относится к совершенно отдельному глобальному пакету. Привычка рассматривать имена пакетов как иерархию очень сильна, но язык никак не навязывает её.
В таблицу символов пакета записываются только идентификаторы, начинающиеся с буквы (или символа нижнего подчеркивания). Все остальные символы хранятся в пакете main, включая все переменные с пунктуацией, такие как $_. Кроме того, при использовании без квалификации идентификаторы STDIN, STDOUT, STDERR, ARGV, ARGVOUT, ENV, INC и SIG принудительно помещаются в пакет main, даже если они используются не по своему встроенному назначению. Если у вас есть пакет, называемый m, s или y, вы не сможете использовать квалифицированную форму идентификатора, потому что она вместо этого будет интерпретироваться как сопоставление шаблонов, замена или транслитерация.
Переменные, начинающиеся с символа нижнего подчеркивания, раньше принудительно помещались в пакет main, но мы решили, что для авторов пакетов полезнее иметь возможность использовать ведущий символ нижнего подчеркивания для обозначения закрытых переменных и имён методов. Однако переменные и функции, имеющие имя, состоящее только из одного символа нижнего подчеркивания, такие как $_ и sub _, по-прежнему помещаются в пакет main. См. также "Синтаксис имён переменных" в perlvar.
eval строковые выражения компилируются в пакете, в котором был скомпилирован eval(). (Присваивания $SIG{}, однако, предполагают, что указанный обработчик сигналов находится в пакете main. Укажите имя обработчика сигнала, если вы хотите иметь обработчик сигнала в пакете.) Для примера посмотрите perldb.pl в библиотеке Perl. Вначале он переключается на пакет DB, чтобы отладчик не вмешивался в переменные программы, которую вы пытаетесь отладить. Однако в различных точках он временно возвращается к пакету main для оценки различных выражений в контексте пакета main (или откуда вы пришли). См. perldebug.
Специальный символ __PACKAGE__ содержит текущий пакет, но (легко) не может быть использован для построения имён переменных. После того, как my($foo) скрыл переменную пакета $foo, к ней всё ещё можно получить доступ, не зная, в каком пакете вы находитесь, как ${__PACKAGE__.'::foo'}.
См. perlsub для других вопросов области видимости, связанных с my() и local(), и perlref относительно замыканий.
Таблицы символов
Таблица символов пакета хранится в хеше с его именем и двумя добавленными двоеточиями. Имя основной таблицы символов — %main::, или %:: для краткости. Аналогично, имя таблицы символов вложенного пакета, о котором говорилось ранее, — %OUTER::INNER::.
Значение в каждом элементе хеша — то, на что вы ссылаетесь, когда используете обозначение *name typeglob.
local *main::foo = *main::bar; Например, с помощью этого можно вывести все переменные в пакете. Стандартная, но устаревшая, библиотека dumpvar.pl и модуль CPAN Devel::Symdump используют это.
Результаты прямого создания новых элементов таблицы символов или изменения элементов, которые ещё не являются typeglob, не определены и могут меняться между выпусками perl.
Присваивание типу typeglob выполняет операцию алиасирования, т.е.
*dick = *richard; приводит к тому, что переменные, подпрограммы, форматы и файловые и каталожные дескрипторы, доступные через идентификатор richard, также становятся доступными через идентификатор dick. Если вы хотите алиасить только определённую переменную или подпрограмму, присвойте ссылку вместо этого:
*dick = \$richard; Это делает $richard и $dick одной и той же переменной, но оставляет @richard и @dick разными массивами. Сложно, не так ли?
Есть небольшое различие между следующими операциями:
*foo = *bar;
*foo = \$bar; *foo = *bar делает сами typeglobs синонимами, в то время как *foo = \$bar делает части SCALAR двух разных typeglob ссылающимися на одно и то же скалярное значение. Это означает, что следующий код:
$bar = 1;
*foo = \$bar; # Make $foo an alias for $bar
{
local $bar = 2; # Restrict changes to block
print $foo; # Prints '1'!
} Выведет '1', потому что $foo содержит ссылку на исходное значение $bar. На то, которое было спрятано local() и которое будет восстановлено по завершении блока. Поскольку к переменным обращаются через typeglob, вы можете использовать *foo = *bar для создания алиаса, который можно локализовать. (Но имейте в виду, что это означает, что у вас не может быть отдельных @foo и @bar, и т.д.)
Важность всего этого заключается в том, что модуль Exporter использует алиасирование typeglob как механизм импорта/экспорта. Возможность правильной локализации переменной, экспортированной из модуля, зависит от того, как она была экспортирована:
@EXPORT = qw($FOO); # Usual form, can't be localized
@EXPORT = qw(*FOO); # Can be localized Вы можете обойти первую ситуацию, используя полное имя ($Package::FOO) там, где вам нужно локальное значение, или перезаписав его, указав *FOO = *Package::FOO в вашем скрипте.
Механизм *x = \$y может использоваться для передачи и возврата ссылок в подпрограммы или из них, если вы не хотите копировать всё целиком. Он работает только при присваивании динамическим переменным, а не лексическим.
%some_hash = (); # can't be my()
*some_hash = fn( \%another_hash );
sub fn {
local *hashsym = shift;
# now use %hashsym normally, and you
# will affect the caller's %another_hash
my %nhash = (); # do what you want
return \%nhash;
} При возвращении ссылка перезапишет слот хеша в таблице символов, указанный typeglob *some_hash. Это несколько хитрый способ передавать ссылки быстро, когда вам не нужно помнить о необходимости явного разыменования переменных.
Другое применение таблиц символов — создание «константных» скаляров.
*PI = \3.14159265358979; Теперь вы не можете изменить $PI, что, вероятно, хорошо. Это не то же самое, что константная подпрограмма, которая может быть оптимизирована на этапе компиляции. Константная подпрограмма — это подпрограмма, прототип которой принимает ноль аргументов и возвращает константное выражение. См. perlsub для получения подробной информации об этом. Пragma use constant — это удобное сокращение для этого.
Вы можете использовать *foo{PACKAGE} и *foo{NAME} для того, чтобы узнать, из какого имени и пакета происходит запись в таблице символов *foo. Это может быть полезно в подпрограмме, которая получает типеглобы в качестве аргументов:
sub identify_typeglob {
my $glob = shift;
print 'You gave me ', *{$glob}{PACKAGE},
'::', *{$glob}{NAME}, "\n";
}
identify_typeglob *foo;
identify_typeglob *bar::baz; Это выводит
You gave me main::foo
You gave me bar::baz Обозначение *foo{THING} также может использоваться для получения ссылок на отдельные элементы *foo. См. perlref.
Определения подпрограмм (и объявления, собственно говоря) необязательно должны находиться в пакете, содержащем таблицу символов. Вы можете определить подпрограмму вне своего пакета, явно квалифицируя имя подпрограммы:
package main;
sub Some_package::foo { ... } # &foo defined in Some_package Это просто сокращение для присваивания типаглоба во время компиляции:
BEGIN { *Some_package::foo = sub { ... } } и не эквивалентно написанию:
{
package Some_package;
sub foo { ... }
} В первых двух вариантах тело подпрограммы находится в лексическом контексте основного пакета, а не в Some_package. Таким образом, что-то вроде этого:
package main;
$Some_package::name = "fred";
$main::name = "barney";
sub Some_package::foo {
print "in ", __PACKAGE__, ": \$name is '$name'\n";
}
Some_package::foo(); выводит:
in main: $name is 'barney' а не:
in Some_package: $name is 'fred' Это также имеет последствия для использования квалификатора SUPER:: (см. perlobj).
BEGIN, UNITCHECK, CHECK, INIT и END
Пять блоков кода со специальными именами выполняются в начале и в конце работы программы Perl. Это блоки BEGIN, UNITCHECK, CHECK, INIT, и END.
Эти блоки кода могут быть префиксованы с помощью sub для имитации подпрограмм (хотя это не считается хорошим стилем). Следует отметить, что эти блоки кода на самом деле не существуют как именованные подпрограммы (несмотря на их внешний вид). Это становится очевидным из того факта, что в программе может быть более одного такого блока кода, и они все будут выполнены в соответствующий момент. Таким образом, вы не можете выполнить ни один из этих блоков кода по имени.
Блок кода BEGIN выполняется как можно скорее, то есть в момент его полного определения, даже до того, как остальная часть содержащего файла (или строки) будет проанализирована. В файле (или строке eval) может быть несколько блоков BEGIN; они будут выполняться в порядке определения. Поскольку блок кода BEGIN выполняется немедленно, он может загрузить определения подпрограмм и т. д. из других файлов вовремя, чтобы они были видны остальной части процесса компиляции и выполнения. После того, как блок BEGIN был выполнен, он немедленно удаляется, и весь код, который он использовал, возвращается в пул памяти Perl.
Блок кода END выполняется как можно позже, то есть после того, как Perl закончил выполнение программы и перед завершением интерпретатора, даже если завершение происходит в результате функции die(). (Но не если он преобразуется в другую программу через exec, или если происходит аварийное завершение из-за сигнала — вы должны сами обрабатывать это (если можете)). В файле может быть несколько блоков END — они будут выполняться в обратном порядке определения; то есть: последний вошел, первый вышел (LIFO). Блоки END не выполняются, когда вы запускаете perl с переключателем -c, или если компиляция завершилась неудачно.
Обратите внимание, что блоки кода END не выполняются в конце строки eval(): если какие-либо блоки кода END созданы в строке eval(), они будут выполнены как любые другие блоки кода END этого пакета в порядке LIFO непосредственно перед завершением интерпретатора.
Внутри блока кода END, $? содержит значение, которое программа передаст в exit(). Вы можете изменить значение $? для изменения значения выхода программы. Будьте осторожны, случайно не изменяя $? (например, выполнив что-либо через system).
Внутри блока END, значение ${^GLOBAL_PHASE} будет равно "END".
Блоки кода UNITCHECK, CHECK и INIT полезны для перехвата перехода между фазой компиляции и фазой выполнения основной программы.
Блоки UNITCHECK выполняются сразу после того, как модуль, их определивший, был скомпилирован. Основной файл программы и каждый загружаемый им модуль являются блоками компиляции, как и строковые evals, код, скомпилированный во время выполнения с помощью конструкции (?{ }) в регулярном выражении, вызовы do FILE, require FILE, и код после переключателя -e в командной строке.
Блоки BEGIN и UNITCHECK не связаны непосредственно с фазой интерпретатора. Они могут быть созданы и выполнены на любой стадии.
Блоки кода CHECK выполняются сразу после завершения начальной фазы компиляции Perl и перед началом выполнения, в порядке LIFO. Блоки кода CHECK используются в наборе инструментов компилятора Perl для сохранения состояния программы после компиляции.
Внутри блока CHECK, значение ${^GLOBAL_PHASE} будет равно "CHECK".
Блоки INIT выполняются непосредственно перед началом выполнения Perl в порядке «первый вошел, первый вышел» (FIFO).
Внутри блока INIT, значение ${^GLOBAL_PHASE} будет равно "INIT".
Блоки CHECK и INIT в коде, скомпилированном с помощью require, строковых do или строковых eval, не будут выполнены, если они появятся после завершения основной фазы компиляции; это может быть проблемой в mod_perl и других постоянных средах, которые используют эти функции для загрузки кода во время выполнения.
При использовании переключателей -n и -p в Perl, BEGIN и END работают так же, как и в awk, как вырожденный случай. Оба блока BEGIN и CHECK выполняются при использовании переключателя -c для проверки синтаксиса только компиляции, хотя ваш основной код не выполняется.
Программа begincheck в итоге проясняет все:
#!/usr/bin/perl
# begincheck
print "10. Ordinary code runs at runtime.\n";
END { print "16. So this is the end of the tale.\n" }
INIT { print " 7. INIT blocks run FIFO just before runtime.\n" }
UNITCHECK {
print " 4. And therefore before any CHECK blocks.\n"
}
CHECK { print " 6. So this is the sixth line.\n" }
print "11. It runs in order, of course.\n";
BEGIN { print " 1. BEGIN blocks run FIFO during compilation.\n" }
END { print "15. Read perlmod for the rest of the story.\n" }
CHECK { print " 5. CHECK blocks run LIFO after all compilation.\n" }
INIT { print " 8. Run this again, using Perl's -c switch.\n" }
print "12. This is anti-obfuscated code.\n";
END { print "14. END blocks run LIFO at quitting time.\n" }
BEGIN { print " 2. So this line comes out second.\n" }
UNITCHECK {
print " 3. UNITCHECK blocks run LIFO after each file is compiled.\n"
}
INIT { print " 9. You'll see the difference right away.\n" }
print "13. It only _looks_ like it should be confusing.\n";
__END__ Классы Perl
В Perl нет специального синтаксиса классов, но пакет может действовать как класс, если он предоставляет подпрограммы, которые действуют как методы. Такой пакет также может наследовать некоторые свои методы от другого класса (пакета), указав имя(а) другого пакета в массиве @ISA (который должен быть глобальным для пакета, а не лексическим).
Для получения дополнительной информации см. perlootut и perlobj.
Модули Perl
Модуль — это просто набор связанных функций в файле библиотеки, то есть пакет Perl с тем же именем, что и файл. Он специально разработан для повторного использования другими модулями или программами. Он может делать это, предоставляя механизм для экспорта некоторых своих символов в таблицу символов любого пакета, использующего его, или он может функционировать как определение класса и делать свои семантики доступными неявно через вызовы методов к классу и его объектам без явного экспорта чего-либо. Или он может делать немного того и другого.
Например, для создания традиционного, не ОО-модуля под названием Some::Module создайте файл с именем Some/Module.pm и начните с этого шаблона:
package Some::Module; # assumes Some/Module.pm
use strict;
use warnings;
# Get the import method from Exporter to export functions and
# variables
use Exporter 5.57 'import';
# set the version for version checking
our $VERSION = '1.00';
# Functions and variables which are exported by default
our @EXPORT = qw(func1 func2);
# Functions and variables which can be optionally exported
our @EXPORT_OK = qw($Var1 %Hashit func3);
# exported package globals go here
our $Var1 = '';
our %Hashit = ();
# non-exported package globals go here
# (they are still accessible as $Some::Module::stuff)
our @more = ();
our $stuff = '';
# file-private lexicals go here, before any functions which use them
my $priv_var = '';
my %secret_hash = ();
# here's a file-private function as a closure,
# callable as $priv_func->();
my $priv_func = sub {
...
};
# make all your functions, whether exported or not;
# remember to put something interesting in the {} stubs
sub func1 { ... }
sub func2 { ... }
# this one isn't always exported, but could be called directly
# as Some::Module::func3()
sub func3 { ... }
END { ... } # module clean-up code here (global destructor)
1; # don't forget to return a true value from the file Затем переходите к объявлению и использованию своих переменных в функциях без каких-либо квалификаций. Для получения подробностей о механизмах и проблемах стиля при создании модулей см. Exporter и perlmodlib.
Модули Perl включаются в вашу программу, используя:
use Module; или
use Module LIST; Это точно эквивалентно
BEGIN { require 'Module.pm'; 'Module'->import; } или
BEGIN { require 'Module.pm'; 'Module'->import( LIST ); } Как особый случай
use Module (); точно эквивалентно
BEGIN { require 'Module.pm'; } Все файлы модулей Perl имеют расширение .pm. Оператор use предполагает это, чтобы вам не приходилось указывать «Module.pm» в кавычках. Это также помогает отличить новые модули от старых файлов .pl и .ph. Имена модулей также пишутся с заглавной буквы, если они не работают как прагмы; прагмы — это по сути директивы компилятора, и их иногда называют «прагматическими модулями» (или даже «прагматами», если вы классик).
Два утверждения:
require SomeModule;
require "SomeModule.pm"; отличаются друг от друга двумя способами. В первом случае все двойные двоеточия в имени модуля, например Some::Module, преобразуются в разделитель каталогов вашей системы, обычно «/». Во втором случае этого не происходит, и он должен быть указан буквально. Другое отличие заключается в том, что первое require подсказывает компилятору, что использование индиректно указываемых объектов, связанных с «SomeModule», как в $ob = purge SomeModule, является вызовами методов, а не функциями. (Да, это действительно может иметь значение).
Поскольку оператор use подразумевает блок BEGIN, импорт семантики происходит сразу после компиляции оператора use, до компиляции остальной части файла. Именно так он может функционировать как механизм прагмы, а также как способ объявить подпрограммы, которые затем будут видны в качестве списочных или унарных операторов для остальной части текущего файла. Это не сработает, если вы используете require вместо use. С require вы можете столкнуться с этой проблемой:
require Cwd; # make Cwd:: accessible
$here = Cwd::getcwd();
use Cwd; # import names from Cwd::
$here = getcwd();
require Cwd; # make Cwd:: accessible
$here = getcwd(); # oops! no main::getcwd() В общем, рекомендуется использовать use Module () вместо require Module, потому что он определяет доступность модуля во время компиляции, а не в середине выполнения вашей программы. Исключением может быть случай, когда два модуля пытаются use друг друга, а каждый также вызывает функцию из другого модуля. В этом случае проще использовать require.
Пакеты Perl могут быть вложены внутри других имён пакетов, поэтому мы можем иметь имена пакетов, содержащие ::. Но если мы использовали это имя пакета непосредственно в качестве имени файла, это привело бы к непрактичным или невозможным именам файлов на некоторых системах. Поэтому, если имя модуля, скажем, Text::Soundex, его определение на самом деле находится в файле библиотеки Text/Soundex.pm.
У модулей Perl всегда есть файл .pm, но с ними также могут быть связаны динамически подключаемые исполняемые файлы (часто с расширением .so) или автозагружаемые определения подпрограмм (часто с расширением .al). В этом случае они будут полностью прозрачны для пользователя модуля. Ответственность файла .pm заключается в загрузке (или организации автоматической загрузки) дополнительной функциональности. Например, хотя модуль POSIX происходит из динамической загрузки и автоматической загрузки, пользователь может просто написать use POSIX для получения всего этого.
Обеспечение потокобезопасности вашего модуля
Perl поддерживает тип потоков, называемых потоками интерпретатора (ithreads). Эти потоки могут использоваться явно и неявно.
Потоки Ithreads работают, клонируя дерево данных, так что данные не разделяются между различными потоками. Эти потоки могут быть использованы, используя модуль threads или выполнив fork() на win32 (поддержка поддельного fork()). Когда поток клонируется, все данные Perl клонируются, однако данные, не являющиеся Perl, не могут быть автоматически клонированы. Perl после версии 5.8.0 поддерживает специальную подпрограмму CLONE. В CLONE вы можете сделать все необходимое, например, обработать клонирование данных, не являющихся Perl, при необходимости. CLONE будет вызвана один раз как метод класса для каждого пакета, в котором она определена (или унаследована от него). Она будет вызвана в контексте нового потока, поэтому все изменения будут внесены в новую область. В настоящее время CLONE вызывается без параметров, кроме имени вызывающего пакета, но код не должен предполагать, что это останется неизменным, так как в будущем могут быть переданы дополнительные параметры для предоставления дополнительной информации о состоянии клонирования.
Если вы хотите клонировать все объекты, вам нужно отслеживать их по пакетам. Это просто делается с помощью хэша и Scalar::Util::weaken().
Perl после версии 5.8.7 поддерживает специальную подпрограмму CLONE_SKIP. Как и CLONE, CLONE_SKIP вызывается один раз на пакет; однако, она вызывается непосредственно перед началом клонирования и в контексте родительского потока. Если она возвращает значение true, то объекты этого класса не будут клонированы; или, скорее, они будут скопированы как неблагословленные, значения undef. Например, если в родительском потоке есть две ссылки на один благословлённый хэш, то в дочернем потоке будет две ссылки на одно неопределённое скалярное значение вместо него. Это предоставляет простой механизм для создания потокобезопасного модуля; просто добавьте sub CLONE_SKIP { 1 } в начало класса, и DESTROY() теперь будет вызываться только один раз на объект. Конечно, если дочерний поток должен использовать объекты, то требуется более сложный подход.
Как и CLONE, CLONE_SKIP в настоящее время вызывается без параметров, кроме имени вызывающего пакета, хотя это может измениться. Аналогично, для будущих расширений возвращаемое значение должно быть единственным значением типа 0 или 1.
СМОТРИ ТАКЖЕ
См. perlmodlib для общих вопросов стиля, связанных с созданием модулей и классов Perl, а также описаний стандартной библиотеки и CPAN, Exporter для получения информации о работе стандартного механизма импорта/экспорта Perl, perlootut и perlobj для углубленного изучения создания классов, perlobj для справочного документа по объектам, perlsub для объяснения функций и области видимости, и perlxstut и perlguts для получения дополнительной информации о написании модулей расширений.
© 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/perlmod