[Moscow.pm] функция не из нашего пакета

Alexander Lourier aml на rulezz.ru
Пн Дек 29 02:24:40 PST 2008


On Monday 29 December 2008 13:10:46 Vladimir V. Perepelitsa wrote:
> 2008/12/29 Alexander Lourier <aml на rulezz.ru>:
> > On Monday 29 December 2008 12:53:43 Dmitry E. Oboukhov wrote:
> >> >> &App::foo и &main::foo это ссылки на одну и ту-же функцию.
> >> >> так что выяснить что является настоящим именем, а что алиасом -
> >> >> неоднозначно. можно к примеру пройтись рекурсивно по всем неймспейсам
> >> >> и найти все имена по равенству ссылок.
> >>
> >> AL> Тоже хотел так ответить сначала. А потом подумал, что caller
> >> каким-то макаром AL> догадывается о настоящем имени.
> >>
> >> это caller вызваный ИЗНУТРИ функции.
> >> там можно и просто тупо __PACKAGE__ или даже __FILE__ юзать.
> >> а надо снаружи функции эту же задачу решить
> >
> > Чуть меняем пример:
> >
> > ==
> > package Ap;
> >
> > use base 'Exporter';
> > our @EXPORT=qw(foo);
> >
> > sub foo
> > {
> >        $_[0]->();
> > }
> >
> > package main;
> >
> > Ap->import();
> >
> > sub foo1
> > {
> >        my @caller = caller(1);
> >
> >        use Data::Dumper;
> >        print STDERR Dumper(\@caller);
> > }
> >
> > foo(\&foo1);
> > ==
> >
> > $VAR1 = [
> >          'main',
> >          'a.pl',
> >          23,
> >          'Ap::foo',
> >          1,
> >          undef,
> >          undef,
> >          undef,
> >          256,
> >          '',
> >          undef
> >        ];
> >
> >
> > На момент вызова caller __PACKAGE__ уже другой (main), но тем не менее,
> > функция идентифицирована как Ap::foo. Это значит лишь одно - что в где-то
> > глубоко в душе Perl помнит исходное имя каждой подпрограммы, даже
> > несмотря на то, что её экспортировали в другой неймспейс.
>
> Извините меня...
> а что еще может вернуть (caller 1)[3], если мы !внутри! сабы Ap::foo
> вызывает другую сабу и проверяем в ней caller(1)?

Вот о чём и говорю. Каким образом caller узнал, что мы внутри Ap::foo, а не 
main::foo? Если бы Ap::foo и main::foo были совершенно симметричными 
алиасами, то Perl не догадался бы, что это Ap::foo. Он бы подумал так - если 
из пакета main вызывается foo(), значит это main::foo. А он так не думает. Он 
лезет в табличку и вспоминает, что foo изначально все-таки объявлялось в Ap, 
даже вспоминает, в каком файле это было и в какой строке. Поэтому, 
практически уверен, что задачу можно решить без всякого рекурсивного обхода 
пакетов, а просто добравшись до этой таблички.

Посмотрел исходники функции caller, ничего не понял в терминах (stash и иже с 
ним) и закрыл. Может кто умеет всё это читать, разберётся.


Подробная информация о списке рассылки Moscow-pm