Создание пакетов и модулей на Perl

Пакеты создаются с помощью ключевого слова 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 и делает всю работу за нас.