Что такое таблица имен (symbol table) в Perl?

Для каждого пакета в Perl создается таблица имен. Таблица имен представляет собой хеш, имя которого совпадает с именем пакета. Ключами этого хеша являются имена глобальных переменных (а так же функций, указателей файлов и т.п.), определенных в текущем пакете. Значения хеша таблицы имен — переменные типа typeglob, которые содержат значения объявленных глобальных переменных.

Новая запись в таблице имен создается в тот момент, когда происходит объявление новой
глобальной переменной. Лексические переменные и «локальные» функции в таблицу не вносятся.
Если для текущего кода пакет не объявлен (директивой package), запись будет помещена в таблицу имен %main:: .

В таблицу имен пакета, отличного от main, могут включаться только те идентификаторы, имена которых начинаются с буквы или символа подчеркивания.

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

Справка: Что такое пакет main?

Main — это пакет верхнего уровня.

Perl поддерживает два специальных имени пакетов:

  • main — пространство имен главной программы. Используется по умолчанию.
  • CORE — пространство имен встроенных функций.

Через main можно получить доступ ко всем используемым в программе пакетам.

Справка: Что такое typeglob?

typeglob — это особенный, внутренний тип данных в perl. Принадлежность к этому типу данных обозначается префиксом «*» . Префикс «*» можно рассматривать как метасимвол, вместо которого может стоять любой из префиксов «$», «@», «%», «&». Т.е. переменная типа typeglob может содержать в себе что угодно.

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

Для получения данных из записей таблицы имен можно использовать поля:

  • PACKAGE — имя пакета, в котором определен текущий идентификатор (имя переменной).
  • NAME — имя идентификатора.
  • SCALAR — ссылка на скалярную переменную идентификатора (если это скалярная переменная).
  • ARRAY — ссылка на массив (если переменная является массивом).
  • HASH — ссылка на хеш (если переменная является хешом).
  • CODE — ссылка на подпрограмму (если идентификатор был создан при объявлении функции).
  • IO, FILEHANDLE — Ссылка на указатель файла.
  • GLOB — Ссылка на typeglob для идентификатора.

Пример 1:

Любая глобальная переменная помещается в пространство имен своего пакета. Можно получить доступ к ее значению, используя таблицу имен. В таблице имен она будет иметь тип данных typeglob, поэтому обращаться к ней нужно через префикс «*».

$variable = 5;
print ${*variable{SCALAR}}; # выведет 5

Пример 2:

use CGI;

print ${*CGI::VERSION{SCALAR}}; # выведет 3.43 

Примеры кода

Пример 1

Вывод содержимого пакета main.

#!/usr/local/bin/perl

foreach (keys %main::) {
        print $_." => ".$main::{$_}."\n";
}

Результат:

%perl main1.pl
version:: => *main::version::
/ => *main::/
stderr => *main::stderr
_ *main::_ *main::CORE::
mro:: => *main::mro::
stdout => *main::stdout
attributes:: => *main::attributes::
 => *main::
stdin => *main::stdin
ARGV => *main::ARGV
INC => *main::INC
ENV => *main::ENV
Regexp:: => *main::Regexp::
UNIVERSAL:: => *main::UNIVERSAL::
_ *main::_ *main::PerlIO::
0 => *main::0
_ *main::_ *main::STDOUT
IO:: => *main::IO::
_ => *main::_
STDERR => *main::STDERR
Internals:: => *main::Internals::
STDIN => *main::STDIN
DB:: => *main::DB::
...
_ *main::_

Пример 2

Допустим, нам хочется получить побольше информации о переменной %ENV, через таблицу имен:

print *main::ENV{HASH};

foreach (keys %{*main::ENV{HASH}}) {
        print $_." => ".${*main::ENV{HASH}}{$_}."\n";
}

Так мы получили полный список переменных окружения и их значений:

%perl main1.pl
HASH(0x800e3e918)SSH_CLIENT => 194.85.195.166 4641 22
HOME => /home/natalie
SSH_CONNECTION => 194.85.195.166 4641 194.85.61.131 22
BLOCKSIZE => K
OSTYPE => FreeBSD
EDITOR => vi
VENDOR => unknown
USER => natalie
GROUP => httpd-natalie
SHLVL => 2
...

Пример 3

Очень простой пример. Объявляем глобальную переменную $count.
Т.к. этот простой скрипт не объявлен как пакет, переменная помещается в пространство имен пакета main. А потом получаем значение переменной через таблицу имен.

our $count = 123;

print ${*main::count};

Результат:

%perl main1.pl
123

В самом деле, использование полей CODE, ARRAY и др. для доступа к значению переменной совсем не обязательно. Однако, в этом случае надо точно знать, ссылку на значение какого типа вернет обращение к таблице имен. Потому что, ссылку нужно соответствующим образом разыменовать. Как это сделать, если вы не имеете никакого понятия, что подразумевается под именем переменной?

В данном примере, count мог оказаться не только скалярной переменной, но и именем массива, и функцией. Если вы работаете с переменной своего модуля - проблем не возникнет. Но если вы импортируете переменные из стороннего пакета - использовать обращение к полям CODE и пр. может оказаться удобнее.

Пример 4

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

use Digest::MD5;

print &{*Digest::MD5::md5_hex{CODE}}("dddd"); 
# выведет 11ddbaf3386aea1f2974eee984542152

Полезные ссылки

Perl. Тип данных typeglob и записи в таблице символов

Таблицы символов и пространства имен

Symbols, Symbol Tables and Packages; Typeglobs

 

Поделись ссылкой с друзьями!

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

Комментариев нет

Комментариев нет.

RSS-лента комментариев к этой записи.

Оставить комментарий