The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME/НАИМЕНОВАНИЕ

perlmod - Perl модули (пакеты и таблицы симолов)

ОПИСАНИЕ

Пакеты

Perl предоставляет механизм изменения пространства имен для защиты пакетов от засорения друг друга всеми своими переменными. Фактически, в Perl нет такой вещи, как глобальные переменные. Инструкция package объявляет единицу компиляции, находящуюся в данном пространстве имен. Область действия объявления пакета начинается от самого объявления и простирается до конца окружающего блока, eval или файла, в зависимости от того, что будет первым (такую же область имеют операторы my() и local()). Неполные (неквалифицированные) динамические идентификаторы будут находится в этом пространстве имен, за исключением тех немногих идентификаторов, которые, будучи неквалифицированными, по умолчанию находятся в пакете main, как будет описано ниже. Инструкция package затрагивает только динамические переменные--включая те, к которым применили local() -- но не лексические переменные, создаваемые при помощи my(). Обычно package будет первым объявлением в файле, который вы подключаете используя операторы do, require или use. Вы можете переключится в пакет в различных местах; это переключение влият только на то, какая таблица символов будет использоваться компилятором до конца этого блока. На переменные и файловые указатели в пакете можно ссылаться из других пакетов, предваряя имя переменной именем пакета и двойным двоеточием: Package::Variable. Если имя пакета отсутствует, подразумевается пакет main. То есть $::sail эквивалентно $main::seil.

В старых пакетах разделителем пакета служила одинарная кавычка, но сейчас предпочтительно использовать двойное двоеточие, оно более человекочитаемо, и также лучше читается в макросах emacs.

Также два двоеточия позволяют С++ программистам чувствовать, что они понимают, что происходит -- в отличии от разделителя одинарная кавычка, позволявшей испытывать похожее чувство 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. Смотрите также "The Syntax of Variable Names" in perlvar.

Обрабатываемые eval-ом строки компилируются в том же пакете, в котором компилируется eval(). (Однако, при присваивании $SIG{} полагается, что обработчик сигнала определен в пакете main. Квалифицируйте имя обработчика сигнала, если хотите использовать обработчик сигнала из пакета.) Для примера взгляните на perldb.pl из библиотеки Perl. В начале работы он переключается на пакет DB так, что отладчик не мешает работать с переменными в отлаживаемой программе.

В различных точках, однако он временно переключает обратно в пакет (package) main для выполнения различных выражений в контексте пакета main (или в том пакете, откуда вы пришли). Смотрите perldebug.

Специальный символ __PACKAGE__ содержит текущий пакет (package), но не может (легко) использоваться для создания имен переменных.

Смотрите perlsub для вопросов, связанных (for other scoping issues related) с my() и local() и perlref для описания замыканий (regarding closures).

Таблицы символов (Symbol Tables)

Таблица символов пакета храниться в хэше с именем, за которым идут два двоеточия. Главной таблицей символов, таким образом, будет %main::, или %:: для краткости. Аналогичным образом таблицой символов для вложенных пакетов является упоминаемое ранее имя %OUTER::INNER::.

Значением в каждой записи хэша является то, что вы имеете в виду когда вы используйте typeglob (глобальный тип) нотацию *name.

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

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

Результаты создания новых записей в таблице символов непосредственно или изменение любой записи, которые уже не являются typeglobs, не определены и являются предметом изменения в следующих релизах perl (subject to change between releases of perl).

Присвоение тайпглобу (глобальном типу, typeglob) выполняет операцию алиасирования (сделать псевдоним, синонимирования, другое имя тому же объекту), т.е. (Assignment to a typeglob performs an aliasing operation, i.e.,)

    *dick = *richard;

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

    *dick = \$richard;

Что делает $richard и $dick той же переменной, но оставляет @richard и @dick независимыми массивами. Хитро, да? (Tricky, eh?)

Существует один тонкое (subtle) различие между следующими инструкциями:

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

*foo = *bar делает тайпглобы синонимами на самих себя, тогда как (makes the typeglobs themselves synonymous while) *foo = \$bar делает СКАЛЯРНЫЕ части двух отдельных тайпглобов (typeglobs) СКАЛЯРНЫХ portions of two distinct typeglobs ссылающимися на теже скалярное значение (refer to the same scalar value). Это означает, что следующий код:

    $bar = 1;
    *foo = \$bar;       # Делает $foo алиасом для $bar

    {
        local $bar = 2; # Изменение ограничено блоком (Restrict changes to block)
        print $foo;     # Напечатает '1'!
    }

Будет печатать '1', потому что $foo содержит ссылку на оригинал $bar. На тот, который был наполнен независимо от local() и, который будет восстановлен, когда блок закончится. Поскольку переменные доступны через тайпглоб (typeglob), вы можете использовать *foo = *bar, чтобы создать псевдоним, который будет локальным. (Однако следует знать, что это означает, что вы не сможете иметь отдельных @foo и @bar, и т.д.)

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

    @EXPORT = qw($FOO); # Обычная форма, не можеть быть локализована
    @EXPORT = qw(*FOO); # Можеть быть локализована

Вы можете обойти (work around) это в первом случае, используя полное имя ($Package::FOO) там, где требуется локальное значение, или путем переопределения его сказав, *FOO = *Package::FOO в скрипте.

Механизм *x = \$y может использоваться для передачи и возврата дешевой ссылки в или из подпрограмм, если вы не хотите, копировать переменную целиком. Это работает только при присваивании динамических переменных, не лексических.

    %some_hash = ();                    # не может быть my()
    *some_hash = fn( \%another_hash );
    sub fn {
        local *hashsym = shift;
        # теперь используем %hashsym нормально, и вы
        # будет влиять на вызвавшего процедуру (caller's) %another_hash
        my %nhash = (); # делаете то, что вы хотите
        return \%nhash;
    }

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

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

    *PI = \3.14159265358979;

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

Определение подпрограммы (и объявления(declarations), коль на то пошло) не обязательно должно находиться в пакете, символьную таблицу которого они занимают. Вы можете определить подпрограмму за пределами пакета явно квалифицируя имя подпрограммы:

    package main;
    sub Some_package::foo { ... }   # &foo определяется в пакете 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 выполняется как можно скорее, как только он полностью определён даже до анализа остального содержимого файла (или строки). Вы можете иметь несколько блоков BEGIN внутри файла (или в выполняемой eval'ом строке); они будут выполнены в порядке определения. Потому что блок BEGIN выполняется немедленно, он может вытащить определения подпрограмм и тому подобного из других файлов во времени, чтобы быть видимым для остальной части во времени компиляции и во время выполнения (compile and run time). После того как блок BEGIN закончился он сразу неопределенным (undefined) и любой используемый код возвращает в Perl пул своей памяти (memory pool).

Блок кода END выполняется настолько поздно насколько это возможно , то есть, после того, как Perl завершает выполнение программы и сразу перед тем, как интерпретатор выйдет (is being exited), даже если это выход в результате функции die(). (Но если он перетекает в другую программу через exec, или выдувается из воды по сигналу--вы должны перехватить (trap) это сами (если вы можете).) Вы можете иметь несколько ENDблоков в файле--они будет выполняться в обратном порядке определения; то есть: последний пришел, первый вышел (last in, first out) (LIFO). END блоки не выполняются при запуске perl с ключем -c, или, если происходит сбой компиляции.

Обратите внимание, что блоки кода END не выполняются в конце строки eval(): если любые блоки кода END создаются в строке eval(), то они будут выполняться так же, как любой другой END блок пакетного кода в порядке LIFO сразу перед тем, как интерпретатор будет выходить (just before the interpreter is being exited).

Внутри блока END, $? содержит значение, которые программа собирается передать exit(). Вы можете изменить $?, чтобы изменить выходное (exit value of the program) значение программы. Остерегайтесь изменения $? случайно (например, запуск чего-то через system).

Внутри блока END, значение ${^GLOBAL_PHASE} будет "END".

Блоки кода UNITCHECK, CHECK и INIT являются полезными для того, чтобы поймать переход между фазой компиляции и фазой выполнения основной программы(execution phase of the main program).

Блоки UNITCHECK выполняются только после того, как юнит, определенный им будет откомпилирован. Файл основной программы и каждый загружаемый ей модуль - это единицы компиляции, такие как строка evals, во время выполнения код компилируется с помощью конструкции (?{ }) в регексе, вызова do FILE, require FILE, и кода после ключа -e командной строки.

Блоки BEGIN и UNITCHECK не связаны непосредственно фазами интерпретатора Perl. Они могут быть созданы и выполняться во время любой фазы.

Блоки кода CHECK выполняются только после фазы окончания начальной компиляции Perl и до начала времени выполнения (run time), в порядке LIFO. Блоки кода CHECK используются в комплекте компилятора Perl (Perl compiler suite) для сохранения скомпилированного состояния программы.

Внутри блока CHECK, значение переменной ${^GLOBAL_PHASE} будет "CHECK".

Блоки INIT выполняются сразу перед началом времени выполнения Perl (Perl runtime begins execution), в последовательности "первый вошел, первый вышл" (FIFO).

Внутри блока INIT , значение ${^GLOBAL_PHASE} будет "INIT".

Блоки CHECK и C <INIT> в коде компилируются с помощью require, строкой C <do>, или строкой eval не будет выполняться, если они возникают после окончания фазы основной компиляции; Это может быть проблемой в mod_perl и других стойких средах (persistent environments), использующих эти функции для загрузки кода во время выполнения.

При использовании ключей -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 merely _looks_ like it should be confusing.\n";

  __END__

  #!/usr/bin/perl

  # begincheck_ru

  print         "10. Обычный код, работающий во время выполнения.\n";

  END { print   "16.  Так что это конец сказки.\n" }
  INIT { print  " 7. Блоки INIT запускают FIFO непосредственно перед рантаймом (runtime).\n" }
  UNITCHECK {
    print       " 4.   И поэтому перед любым блоком CHECK.\n"
  }
  CHECK { print " 6.   Так что это шестая строка.\n" }

  print         "11.   Она выполняется последовательно, конечно.\n";

  BEGIN { print " 1. BEGIN блоки запускаются FIFO во время компиляции.\n" }
  END { print   "15.   Читайте perlmod для остальной части рассказа.\n" }
  CHECK { print " 5. CHECK блоки запускаются LIFO после всей компиляции.\n" }
  INIT { print  " 8.   Запустить это снова, используя ключ Perl -c.\n" }

  print         "12.   Это анти запутанный код.\n";

  END { print   "14. END блоки запускаются LIFO во время времени выходя из программы.\n" }
  BEGIN { print " 2.   Так что эта линия выходит второй.\n" }
  UNITCHECK {
   print " 3. UNITCHECK блоки запускаются LIFO после того, как каждый файл откомпилируется.\n"
  }
  INIT { print  " 9.   Вы сразу увидите разницу.\n" }

  print         "13.   Это просто _выглядит_ так, как она должна быть запутанным. (It merely _looks_ like it should be confusing.)\n";

  __END__

Perl Классы

Не существует специального синтаксиса класса в Perl, но пакет может действовать как класс, если он предоставляет подпрограммы в качестве методов. Такие пакеты могут также предоставить некоторые из методов его от другого класса (пакета) перечисляя другие имена пакета в глобальной массиве @ISA (который должен быть глобальным пакетом, не локальным (package global, not a lexical)).

Подробнее об этом см. perlootut и perlobj.

Perl Модули

Модуль это просто набор связанных функций в файле библиотеки, т.е. Perl пакет с тем же именем, что и файл. Он специально предназначен для повторного использования в других модулях или программ. Он может сделать это предоставляя механизм для экспорта некоторых из его символов в таблицу символов любого пакета, котрый его использует, или он может функционировать как определение класса и сделать доступным свою семантику неявно через вызовы методов в классе и его объекты, без явного экспорт процедур. Или он может быть и тем и другим.

Например чтобы начать традиционный, не-OO модуль под названием Some::Module, создайте файл с именем Some/Module.pm и начните с помощью этого шаблона:

    package Some::Module;  # assumes Some/Module.pm

    use strict;
    use warnings;

    BEGIN {
        require Exporter;

        # set the version for version checking
        our $VERSION     = 1.00;

        # Inherit from Exporter to export functions and variables
        our @ISA         = qw(Exporter);

        # 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 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 файлов. Имена модулей также пишутся большими буквами (капитализируются), если они не функционируют как прагмы; прагмы здесь выступают, как директивы компилятора, и иногда называются "прагматичными модулями" ( "pragmatic modules") (или даже "pragmata" если вы являетесь последователем классицизма).

Эти два выражения:

    require SomeModule;
    require "SomeModule.pm";

отличаются друг от друга в двух случаях. В первом случае, любое двойное двоеточие в имени модуля, например Some::Module, переводятся в вашей системе в разделитель каталогов, обычно "/". Второй случай в том, что имя и должно быть указаны буквально. Другая разница в том, что видя первый require клей в компиляторе использующий косвенное дополнение нотации с участием "SomeModule", как в $ob = purge SomeModule, является вызовом метода, а не вызов функции. (Да, в этом действительно может быть различие.)

Потому что выражение use подразумевает блок BEGIN, импорт семантики происходит, как только инструкция use компилируется, перед компиляцией остальной части файла. Это то, как это может функционировать в качестве pragma механизма, а также как модули способны объявите подпрограммы, которые затем отображаются как список или унарные операторы для остальной части текущего файла. Это не будет работать, если вы используете 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 вместо use.

Perl пакеты могут быть вложены в другие имена пакетов, поэтому мы можем иметь имена пакетов, содержащих ::. Но если мы использовали это имя пакета непосредственно в качестве имени файла он будет для нас громоздким или невозможным именем файла на некоторых системах. Поэтому, если имя модуля, скажем, Text::Soundex, то его определение на самом деле находится в библиотеке файла Text/Soundex.pm.

Модули Perl всегда имеют файл .pm, но там также могут быть динамически связанные исполняемые файлы (часто заканчиваются на .so) или автозагружаемые определения подпрограмм (autoloaded subroutine definitions) (часто заканчиваются в .al), связанные с модулем. Если это так, то они будут полностью прозрачны для пользователя модуля. На файле .pm лежит ответственность по загрузке (или организации автозагрузки) любых дополнительных функциональных возможностей. Например, хотя для модуль POSIX случается делать и динамическую загрузку и автозагрузку (POSIX module happens to do both dynamic loading and autoloading), пользователь может сказать просто use POSIX, чтобы получить и то и другое.

Делаем ваш модуль потокозащищенным (Making your module threadsafe)

Perl поддерживает тип потоков называемый интерпретатор потоков (interpreter threads)(ithreads). Эти потоки могут использоваться явно и неявно.

Ithreads работают путем клонирования дерева данных таким образом, чтобы данные не разделялись между различными потоками. Эти потоки могут быть использованы с помощью модуля threads или выполнив fork() на win32 (поддержка поддельной функции fork() ). Когда поток клонируется - все данные Perl клонируются, хотя не-Perl данные не могут клонироваться автоматически. Perl 5.8.0 имеет поддержку специальной подпрограммы CLONE. С CLONE вы можете делать все, что вам нужно сделать, как например обрабатывать клонированные не-Perl данные, в случае необходимости. CLONE будет вызван один раз как метод класса для каждого пакета, в котором о определен (или геде его наследуют). Он будет вызываться в контексте нового потока, таким образом, все изменения будут сделаны уже в новой области. В настоящее время CLONE вызывается без параметров не считая имени вызвавшего пакета, но код не должен предполагать что это будет оставаться без изменений, так как, вероятно, что в будущем дополнительные параметры будут передаваться, чтобы в дать больше информации о состоянии клонирования.

Если вы хотите КЛОНИРОВАТЬ (CLONE) все объекты, вам нужно будет отслеживать изменения в их пакетах. Это просто выполняется с помощью хэша и Scalar::Util::weaken().

Perl после 5.8.7 имеет поддержку для специальной подпрограммы CLONE_SKIP. Как и С<CLONE> CLONE_SKIP вызывается один раз для каждого пакета, однако, он вызывается непосредственно перед началом клонирования и в контексте родительского потока. Если он возвращает значение true, то объекты этого класса не будут клонироваться; или, скорее они будут скопированы как неблагословленные, неопределенные значения (unblessed, undef value). Например: если в родителе есть две ссылки на один благословленный хэш, то у ребенка вместо этого будут две ссылки на одно неопределенное скалярное значение. Это обеспечивает простой механизм для создания потокозащищенного(threadsafe) модуля; просто добавьте sub CLONE_SKIP { 1 } в верхней части класса и DESTROY() будет теперь вызываться только один раз за объект. Конечно, если дочерний поток требует, чтобы использовались объекты, то требуется более сложный подход.

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

SEE ALSO

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

ПЕРЕВОДЧИК

  • Николай Мишин <mi@ya.ru>

  • Андрей Асякин <asan999 at gmail.com>