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 делает сами typeglob синонимами, в то время как *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 runtime в порядке «первый пришёл – первый вышел» (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 вызывается один раз на пакет; однако, она вызывается непосредственно перед началом клонирования и в контексте родительского потока. Если она возвращает истинное значение, объекты этого класса не будут клонированы; или же они будут скопированы как неблагословлённые, значения undef. Например: если в родительском потоке есть две ссылки на один благословлённый хеш, то в дочернем потоке будет две ссылки на одно неопределённое скалярное значение вместо этого. Это обеспечивает простой механизм для обеспечения потокобезопасности модуля; просто добавьте sub CLONE_SKIP { 1 } в начало класса, и DESTROY() теперь будет вызываться только один раз на объект. Конечно, если дочернему потоку необходимо использовать объекты, то требуется более сложный подход.
Как и CLONE, CLONE_SKIP в настоящее время вызывается без параметров, кроме имени вызывающего пакета, хотя это может измениться. Аналогично, для поддержки будущего расширения возвращаемое значение должно быть единственным значением 0 или 1.
СМОТРИТЕ ТАКЖЕ
См. perlmodlib для общих вопросов стиля, связанных с созданием модулей и классов Perl, а также описания стандартной библиотеки и CPAN, Exporter для того, как работает механизм импорта/экспорта Perl, perlootut и perlobj для углублённой информации о создании классов, perlobj для справочного документа по объектам, perlsub для объяснения функций и области видимости, а также perlxstut и perlguts для получения дополнительной информации о написании модулей расширения.
© 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.30.3/perlmod