Spec-Zone.ru › Perl 5.38

perlmod

СОДЕРЖАНИЕ

  • ИМЯ
  • ОПИСАНИЕ
    • Документ, который вы искали?
    • Пакеты
    • Таблицы символов
    • BEGIN, UNITCHECK, CHECK, INIT и END
    • Классы Perl
    • Модули Perl
    • Делаем ваш модуль потокобезопасным
  • СМОТРИТЕ ТАКЖЕ

ИМЯ

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".

Использование ' в качестве разделителя пакетов устарело и будет удалено в Perl 5.40.

Пакеты сами могут содержать разделители пакетов, как в $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.

local *main::foo    = *main::bar;

Вы можете использовать это, например, для вывода всех переменных в пакете. Стандартная, но устаревшая библиотека dumpvar.pl и модуль CPAN Devel::Symdump используют это.

Результаты создания новых записей в таблице символов напрямую или изменения любых записей, которые не являются уже типаглобами, не определены и могут изменяться между выпусками perl.

Присвоение типаглобу выполняет операцию алиасирования, т.е.

*dick = *richard;

приводит к тому, что переменные, подпрограммы, форматы и дескрипторы файлов и каталогов, доступные через идентификатор richard, также становятся доступными через идентификатор dick. Если вы хотите сделать алиас только для определенной переменной или подпрограммы, присвойте ссылку вместо этого:

*dick = \$richard;

Это делает $richard и $dick одной переменной, но оставляет @richard и @dick отдельными массивами. Сложно, да?

Существует небольшая разница между следующими операторами:

*foo = *bar;
*foo = \$bar;

*foo = *bar делает типаглобы сами по себе синонимичными, а *foo = \$bar делает части SCALAR двух разных типаглобов, ссылающихся на одно и то же скалярное значение. Это означает, что следующий код:

$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() и которое будет восстановлено по окончании блока. Поскольку к переменным обращаются через типаглобы, вы можете использовать *foo = *bar для создания алиаса, который можно локализовать. (Но имейте в виду, что это означает, что у вас не может быть отдельных @foo и @bar, и т.д.)

Важность всего этого заключается в том, что модуль Exporter использует алиасирование типаглобов как механизм импорта/экспорта. Возможность правильной локализации переменной, которая была экспортирована из модуля, зависит от того, как она была экспортирована:

@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;
    }

При возвращении ссылка перепишет слот хэш-таблицы, указанный типаглобом *some_hash. Это несколько хитрый способ передавать ссылки дёшево, когда вам не нужно помнить, что нужно явно разыменовывать переменные.

Другое применение таблиц символов - создание "константных" скаляров.

*PI = \3.14159265358979;

Теперь вы не можете изменить $PI, что, вероятно, хорошо. Это не то же самое, что константная подпрограмма, которая может быть оптимизирована на этапе компиляции. Константная подпрограмма - это подпрограмма, прототипированная для принятия ноль аргументов и возвращающая константное выражение. См. perlsub для получения подробной информации об этом. Предикат 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

Это просто сокращение для присваивания typeglob во время компиляции:

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".

Аналогичны блоку END блоки defer, хотя они работают на протяжении срока службы отдельных областей видимости блоков, а не всей программы. Они документированы в "defer" в perlsyn.

Блоки кода UNITCHECK, CHECK и INIT полезны для перехвата перехода между фазой компиляции и фазой выполнения основной программы.

Блоки UNITCHECK выполняются сразу после того, как единица, которая их определила, была скомпилирована. Основной файл программы и каждый модуль, который он загружает, являются единицами компиляции, так же как и строковые eval, код, скомпилированный во время выполнения с использованием конструкции (?{ }) в регулярном выражении, вызовы 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 v5.36;

# 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 вызывается один раз на пакет; однако, она вызывается непосредственно перед началом клонирования и в контексте родительского потока. Если она возвращает истинное значение, объекты этого класса не будут клонированы; или, скорее, они будут скопированы как неблагословенные, неопределённые значения. Например, если в родительском потоке есть две ссылки на один благословенный хеш, то в дочернем потоке будет две ссылки на одно неопределённое скалярное значение вместо этого. Это обеспечивает простой механизм для создания потокобезопасного модуля; достаточно добавить sub CLONE_SKIP { 1 } в начало класса, и DESTROY() теперь будет вызываться только один раз на объект. Конечно, если дочернему потоку нужно использовать объекты, потребуется более сложный подход.

Как и CLONE, CLONE_SKIP в настоящее время вызывается без параметров, кроме имени вызывающего пакета, хотя это может измениться. Аналогично, чтобы обеспечить возможность будущего расширения, возвращаемое значение должно быть одиночным значением 0 или 1.

СПРАВКА

См. perlmodlib по общим вопросам стиля, связанным с созданием модулей и классов Perl, а также описание стандартной библиотеки и CPAN, Exporter для работы механизма импорта/экспорта Perl, perlootut и perlobj для глубокого изучения создания классов, perlobj для справочного документа по объектам, perlsub для объяснения функций и области видимости, и perlxstut и perlguts для получения дополнительной информации по написанию расширяющих модулей.

© 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/perlmod

Spec-Zone.ru

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