Статья
Версия для печати
Обсудить на форуме
Perl :: модули, пакеты, классы, объекты


Содержание


Предисловие.

Хотелось бы сегодня вкратце рассказать об обширной области Perl - о модулях, пакетах, классах и работе с ними. В следующих статьях я расскажу о наследовании и связывании переменных (это тоже имеет отношение к классам). Материал рассчитан на начинающих, но по битам разжевывать не буду. Для более подробного изучения следует обратиться к мануалам Perl. Очередной раз рекомендую книгу Perl Programming издательства O'Reilly (Программирование на Perl - переводное русскоязычное издание издательства Символ), среди авторов которой присутствует имя создателя Perl - Ларри Уолла.

Немного определений.

Что такое модуль? Это отдельный файл с частью программы.
Что такое пакет? Это пространство имен, обозначаемое командой package.
Что такое класс? Это то же самое, что и пакет.
Что такое объект? Это ссылка на любой встроенный тип данных, "освященная" командой bless.
Что такое связанная переменная? Это переменная (не ссылка), "связанная" с классом командой tie.

Соглашение именования.

На самом деле никаких ограничений нет, но, если придерживаться некоторых правил, то это уменьшит вероятность ошибки в коде.
Имена переменных и функций принято начинать с маленькой (строчной) буквы, а имена пакетов (классов) и модулей - с большой (прописной).
Вообще, имена модулей допустимо именовать как угодно, но если вы используете для загрузки команды use или require с "голыми" именами, то правильно будет именовать именно с большой буквы.
Расширение имен файлов (суффикс) принято такое: pl - для главного модуля, pm - для загружаемых модулей.

Модули.

Модуль не требует никакого особого оформления. Если модуль содержит одноименный пакет, то обычно его начинают с команды package.

Код: (Perl)
# файл Example1.pm
package Example1;

Загружают модуль командами use и require. Команда use загружает модуль на этапе компиляции, когда Perl находит ее в процессе синтаксического разбора. Команда require загружает модуль на этапе исполнения, когда логика выполнения доходит до этой команды.
Форматы команд:

Код: (Perl)
# Загружает модуль Module.pm
use Module;

# загружает модуль Dir1/Dir2/Module.pm
use Dir1::Dir2::Module;

# Загружает модуль и импортирует из него в текущее пространство имен имена name1, name2 и name3
# Требуется наличие в модуле одноименного пакета и метода import
use Module qw(name1 name2 name3);

# Загружает файл, заданный выражением
use EXPR;

Команда require имеет точно такой же формат.
Загружаемые файлы ищутся в директориях, указанных в массиве @INC. Имена успешно загруженных модулей помещаются в хеш %INC (имя используются в качестве ключа, а значение содержит полный путь к файлу).

Если есть неуверенность в том, что модуль существует, и нужно обработать ошибку, то можно применить блок eval.

Код: (Perl)
eval { require Module; };
if ($@)
{
        # error...
}

Также можно обратить внимание на команду do в форме со строковым выражением.

Пакеты и классы.

Как я уже написал выше, пакет - это пространство имен. В одном файле можно последовательно объявлять несколько пакетов, а также можно объявлять несколько раз один и тот же пакет. Команда package влияет на интерпретацию имен глобальных переменных, у которых не указано имя пакета (не квалифицированные имена), в том числе на переменные, объявленные с ключевым словом local, и действует до конца блока, в котором она определена, либо до следующего переназначения пакета. На ранее объявленные переменные с ключевым словом our команда не влияет.
Пакетом по умолчанию является main. Встроенные команды находятся в пакете Core.
Код: (Perl)
package Class1;
$x = 1; # $Class1::x

package Class2;
$x = 2; # $Class2::x

package Class1;
print $x; # $Class1::x
print $Class2::x;

Объекты.

Объект создается методом "освящения" ссылки на встроенный тип данных именем класса с помощью команды bless. Функция ref() возвращает для такой ссылки имя класса.
Методы класса являются простыми функциями пакета и отличаются тем, что в качестве первого параметра в метод передается ссылка на объект или имя класса, если метод вызван как статический.
Статические члены класса определяются как глобальные переменные пакета.
Данные объекта полностью динамичны и зависят от используемого типа ссылки. Чаще всего применяют хеш - это позволяет использовать именованные данные.
В Perl для конструктора нет зарезервированного имени, как в C++. Любая функция может быть конструктором. Конструктора может вообще не быть - связать ссылку с классом можно в любом месте программы. Для деструктора в Perl принято имя DESTROY. Деструктор вызывают во время уничтожения объекта при сборке мусора. То есть, если нужно высвободить какие-либо ресурсы типа файлов или подключений к БД, то лучше сделать отдельный метод и принудительно его вызывать.

Код: (Perl)
package Class1;

# самый примитивный конструктор
sub simple
{
        return bless {};
}

# классический пример конструктора, поддерживающего наследование
sub new
{
        my $invocant = shift; # первый параметр - ссылка на объект или имя класса
        my $class = ref($invocant) || $invocant; # получение имени класса
        my $self = { @_ }; # ссылка на анонимный хеш - это и будет нашим новым объектом, инициализация объекта

        bless($self, $class); # освящаем ссылку в объект

        return $self; # возвращаем объект
}

# пример деструктора
sub DESTROY
{
        my $self = shift;

        # тут можно выполнить какие-либо действия
}

# варианты использования конструктора для создания объекта
my $object1 = new Class1;
my $object2 = Class1->new('param1', 1, 'param2', 'abc', param3 => 333);
my $object3 = $object1->new();

В вышеприведенном примере конструктора применены некоторые ухищрения.

Код: (Perl)
my $class = ref($invocant) || $invocant;

Получение имени класса.
Если дочерний класс использует в качестве конструктора метод родительского класса, то он автоматом получит в качестве первого параметра имя дочернего класса. Если же передать ссылку на объект, то будет создан новый объект того же типа.

Код: (Perl)
my $self = { @_ };

Инициализация объекта.
Этого можно не делать или предварительно разобрать и проверить параметры. Просто это удобная форма инициализации.

Метод можно вызывать как статический (используя имя класса) или как метод объекта (используя ссылку на объект). Кроме того, есть две синтаксические формы записи.

Код: (Perl)
# классическая синтаксическая форма - взята из C++
$object->method($arg1, $arg2, $arg3); # метод объекта
Class1->method($arg1, $arg2, $arg3); # метод класса

# вторая синтаксическая форма
method $object $arg1, $arg2, $arg3; # метод объекта
method Class1 $arg1, $arg2, $arg3; # метод класса

Заметьте, что во второй форме аргументы после объекта отделяются символами пробелов, а не запятой.
Классическая форма предпочтительнее, т.к. более однозначна с точки зрения синтаксиса. Совсем однозначно будет, если после имени класса поставить "::".

Код: (Perl)
method Class1:: $arg1, $arg2, $arg3;
Class1::->method($arg1, $arg2, $arg3);

Не стоит путать вызов метода с вызовом функции. Ведь в этом случае первым параметром не передается имя класса - параметров на один меньше.

Код: (Perl)
Class1::method($arg1, $arg2, $arg3); # вызов функции

Напутствие.

Если этого маленького ликбеза вам недостаточно - посмотрите мануалы, идущие с Perl. В непонятных случаях задавайте вопросы на наш форум. Одна только просьба: конкретизируйте, пожалуйста, ваши вопросы.

Чернышов Роман (RXL) 20.12.2007
Версия для печати
Обсудить на форуме