Пакеты создаются с помощью ключевого слова package. Пакет верхнего уровня или первоначальный текущий пакет - это "main", то это значит что начинается новый текущий пакет. Текущий пакет определяет таблицу имен для поиска переменных, функций и т.д.
Пример создания пакетов:
#!/usr/bin/perl -w { package Array; $name = "Array"; } { package String; $name = "String"; } print " package Array name = $Array::name\n package String name = $String::name \n";
Пакеты позволяют разделять глобальное пространство имен.
Модуль реализуется просто как пакет, определенный в отдельном файле с тем же именем и .pm в конце. Т.е. модули это те же пакеты, только каждый в своем файле.
Модули могут подключаться с помощью директив do, use и require. Для поключения модуля он должен находиться либо в тойже папке что и использующая его программа, либо в папке указанной в массиве @INC:
perl -V
При подключении модуля с помощью директивы do он в этой точке встраивается в выполняемую программу. Т.е. код модуля будет встраиваться каждый раз без учета был ли он уже подключен где либо ранее. К примеру, создадим модуль используюущий Sorting.pm :
#!/usr/bin/perl -w package ExtendedSorting; do 'Sorting.pm'; sub Hello{ @array=qw( 1 2 3 4 5 ); Sorting::print_array(\@array); print "ExtendedSorting sub Hello\n"; }
Создадим пограмму, в которой хотим использовать и функции модуля Sorting.pm и модуля ExtendedSorting.pm. Подключим оба модуля с помощью директивы do:
#!/usr/bin/perl -w do 'ExtendedSorting.pm'; do 'Sorting.pm'; @array = qw( 1 2 3 4 5); Sorting::print_array(\@array); ExtendedSorting::Hello();
При использовании директивы do для подключения модулей, это приведет к повторному подключению кода в программу при её запуске. Если вы включите вывод предупреждений (как в программе выше), то увидете соответствующее предупреждение:
Subroutine sort_array redefined at Sorting.pm line 5. Subroutine print_array redefined at Sorting.pm line 9.
Для того чтобы избавиться от ошибки с повторным подключением модулей можно использовать директиву require. Если изменить код описанный выше и заменить
везде do на require. То предупреждения исчезнут.
Так как с помощью директив do и require модули подключаются на этапе выполнения, то основной их проблемой является, то что нужно подключать модуль перед его использованием. Т.е. при использовании следующего кода perl выдаст ошибку:
# cat do.pl
#!/usr/bin/perl -w
#Попробуем подключить модуль в конце
#require 'ExtendedSorting.pm';
require 'Sorting.pm';
@array = qw( 1 2 3 4 5);
Sorting::print_array(\@array);
ExtendedSorting::Hello();
require 'ExtendedSorting.pm';
При компиляции ошибки нет. А при выполнении perl выдает ошибку, что библиотека не найдена:
# perl -c do.pl do.pl syntax OK # ./do.pl Undefined subroutine &ExtendedSorting::Hello called at ./do.pl line 7.
Для того чтобы решить эту проблему и не следить за тем, где используется функция модуля выше или ниже его подключения, необходимо использовать директиву use.
При подключении модуля через директиву use :
- модуль подключается единожды
- место подключения модуля в программе, не влияет на использование его функций в той же программе.
Проблемы эти решаются потому, что обработка директивы use идет на стадии компиляции, а не на стадии выполнения.
Перепишем пример следующим образом :
#!/usr/bin/perl -w #Решаем проблему повторного подключения use Sorting; @array = qw( 1 2 3 4 5); Sorting::print_array(\@array); ExtendedSorting::Hello(); #Решаем проблему использования функций модуля до его подключения use ExtendedSorting;
При использовании директивы use немножко меняется синтаксис. В конце имени модуля .pm указывать не нужно. Плюс сам модуль всегда должен возвращать значение true. Поэтому нам необходимо переписать и подключаемый модуль ExtendedSorting.pm и в конце добавить одну строку 1;
#!/usr/bin/perl -w package ExtendedSorting; use Sorting; sub Hello{ @array=qw( 1 2 3 4 5 ); Sorting::print_array(\@array); print "ExtendedSorting sub Hello\n"; } 1;
В принципе следующие два примера работают аналогично :
.... #Используем use use ExtendedSorting; .... #Используем require BEGIN { require 'ExtendedSorting.pm'; }
Так как BEGIN это самый первый блок который выполняется программой, вне зависимости его местоположения в коде. Но лучше все-таки использовать директиву use так как она реализует еще одну удобную функциональность - импорт функций из модуля. Об этом будет рассказано ниже. Т.е. при использовании use в блоке BEGIN на этапе компиляции происходит :
BEGIN { require 'ExtendedSorting.pm'; ExtendedSorting->import; }
Если Ваши модули лежат не в стандартных папках указанных в @INC и не в тойже директории, что и вызываемая их программа, то Вы можете использовать директиву use lib. При использовании этой директивы Вы указываете компилятору, где искать ( откуда подключать) необходимые модули. К примеру,
#!/usr/bin/perl -w
#Теперь модули можно расположить в данной папке
use lib '/home/perl';
use ExtendedSorting;
use Sorting;
@array = qw( 1 2 3 4 5);
Sorting::print_array(\@array);
ExtendedSorting::Hello();
Дополнить массив @INC можно указав переменную PERL5LIB в профиле пользователя.
Для того, чтобы обращаться к функции пакета не по полному пути, к примеру, Sorting::sort_array(), а только по имени желаемой функции sort_array(),
необходимо произвести экспортирование. Делается это с помощью стандартного модуля Exporter.
Сначала Вам нужно произвести наследование от этого класса:
use base Exporter;
Затем указать какие функции модуля Вы хотите экспортировать ( с помощью глобального массива @EXPORT):
our @EXPORT = qw(sort_array print_array);
Теперь при использовании пакета Sorting.pm указывать полный путь до используемой функции не надо.
Пример пакета с экспортированием:
#!/usr/bin/perl -w package Sorting; use base Exporter; our @EXPORT=qw(sort_array print_array); sub sort_array { $ref_array = shift; @{$ref_array} = sort{ $a <=> $b } @{$ref_array}; } sub print_array{ $ref_array = shift; for $item (@{$ref_array}){ print $item,"\n"; } } 1;
Использование функций напрямую в программе main.pl:
#!/usr/bin/perl -w use Sorting; @array = qw(1 23 56 6 12); #array isn't sorted print_array(\@array); #a sorting of the array sort_array(\@array); #array is sorted print_array(\@array);
Как было описано выше use Sorting; преобразуется на этапе компиляции в блок:
BEGIN { require Sorting; Sorting->import; }
Если модуль ничего не экспортирует ( функции import нет), то ничего не происходит. А в нашем примере модуль Exporter имеет функцию import и делает всю работу за нас.