Вызов подпрограммы в ООП Perl - PullRequest
7 голосов
/ 27 октября 2010

При просмотре некоторого кода, который я взял на себя, я наткнулся на эту строку:

 my @files = My::Module::DB::raw_info->search_like(customer_handle => $config->{client}, feed => $config->{site}, arrival =>"$date")

Я знаю, что это возвращает массив из пакета с именем My::Module::DB::raw_info.

я не уверен (и я только изучаю ООП), это то, к чему относится ->search_like.

Я не видел это как переменную или подпрограмму в My::Module::DB::raw_info

Любые подсказки приветствуются.Я только начинаю изучать этот материал.Это как купаться в огне.(Я знаю, что позже я стану счастливее) Yikes!

Ответы [ 6 ]

8 голосов
/ 27 октября 2010

Вероятно, это связано с тем, что метод унаследован от базового класса.Однако в чрезвычайно странных ситуациях он МОЖЕТ также динамически вводиться в пространство имен модуля, что гораздо сложнее понять.

Вы можете найти свой саб или путем перебора, или путем определения базового класса модуля (и, возможно, выше по цепочке наследования) и поиска только кода базовых классов.Я покажу, как сделать оба:


Поиск методом грубой силы : Это, вероятно, простейшее решение в сложных случаях, поскольку подводная лодка могла быть введена впространство имен модуля динамически с помощью модуля, не являющегося предком, и поиск модулей-предков не является простым на 100% из-за множественных способов определения наследования, которое можно было бы использовать (использовать базу, использовать родителя, вещи Moose, вещи AUTOLOADED)

Firstвыясните, какие другие модули загружены с помощью My :: Module

perl -e 'use My::Module::DB::raw_info; print "$INC{$_}\n" foreach keys %INC'

Это распечатает местоположение ВСЕХ этих модулей

Затем найдите подопределение во ВСЕМ этом коде (следующие должны быть все в одну строку, я делю его для удобства чтения на 2 строки):

grep search_like 
   `perl -e 'use My::Module::DB::raw_info; print "$INC{$_}\n" foreach keys %INC'`

Если это возвращает слишком много результатов, измените grep на

grep "sub search_like"
   `perl -e 'use My::Module::DB::raw_info; print "$INC{$_}\n" foreach keys %INC'`

Это найдетВы определяете в каком модуле My :: Module :: DB :: raw_info наследуетесь без фактического анализа кода модуля на наследование.


Наследование :

Найдите родителя модуля, используя ISA, следующим образом:

perl -e 'use My::Module::DB::raw_info; print "@My::Module::DB::raw_info::ISA\n";'

Для пояснения, это работает только для "классически унаследованных" модулей, использующих @ISA, а не Moose.,Это также не работает, если подпрограмма вызывается с помощью AutoLoader или динамически внедряется в таблицу символов, что может происходить в любом коде, не обязательно в родительском.

5 голосов
/ 27 октября 2010

Вероятная причина вашей загадки в том, что My :: Module :: DB расширяет какой-то другой класс.Найдите блок вдоль линий

use parent Some::Module;

или

BEGIN { extends Some::Module }

в верхней части My / Module / DB.pm

Редактировать: Как указывают некоторые полезные комментарии ниже, существует несколько способов создать подкласс класса Perl, но, вероятно, это наиболее распространенный способ.(Может быть.)

2 голосов
/ 27 октября 2010

Вы можете использовать модуль ядра Devel::Peek для просмотра внутренних данных, содержащихся в ссылках на подпрограммы.

Чтобы получить ссылку на подпрограмму из метода OO, вы используете метод ->can(...) для всех объектов.

my $code_ref = My::Module::DB::raw_info->can('search_like');

и затем вы можете распечатать информацию:

use Devel::Peek 'Dump';

Dump($code_ref);

Согласно документации Devel::Peek, вы должны получить что-то вроде этого:

Ссылка на подпрограмму выглядит следующим образом:

    SV = RV(0x798ec)
      REFCNT = 1
      FLAGS = (TEMP,ROK)
      RV = 0x1d453c
    SV = PVCV(0x1c768c)
      REFCNT = 2
      FLAGS = ()
      IV = 0
      NV = 0
      COMP_STASH = 0x31068  "main"
      START = 0xb20e0
      ROOT = 0xbece0
      XSUB = 0x0
      XSUBANY = 0
      GVGV::GV = 0x1d44e8   "MY" :: "top_targets"
      FILE = "(eval 5)"
      DEPTH = 0
      PADLIST = 0x1c9338

Это показывает, что

  • подпрограмма не является XSUB (поскольку START и ROOT отличны от нуля, а XSUB равен нулю);
  • чтобы он был скомпилирован в основной пакет;
  • под именем MY :: top_targets;
  • внутри 5-го eval в программе;
  • в настоящее время не выполняется (см. DEPTH);
  • он не имеет прототипа (поле PROTOTYPE отсутствует).

Итак, COMP_STASH показывает вам, где был скомпилирован код, а GVGV :: GV показывает вам полное имя сабвуфера.

1 голос
/ 27 октября 2010

В ответ на вопрос «В чем я не уверен, а я только изучаю ООП (благодаря увольнению нашего разработчика), это то, на что ссылается« -> search_like ». класс, который принимает пары «имя-значение» в качестве входных параметров ( Раздел 10.7 Perbook Cookbook).

К вашему сведению, другая книга, которую я считаю очень полезной, - Программирование на Perl .

1 голос
/ 27 октября 2010

Возможно, это какой-то унаследованный метод.Прочитайте немного о наследовании Perl , найдите какое-либо присвоение @ISA в определении вашего модуля.

1 голос
/ 27 октября 2010

Метод может быть определен в суперклассах My::Module::DB::raw_info. Вставьте эту строку перед звонком на search_like:

print @My::Module::DB::raw_info::ISA;

Теперь посмотрите на эти классы.

Если это не работает, вы можете использовать Devel :: Peek Dump(), чтобы увидеть, откуда появилась подпрограмма:

use Devel::Peek;
Dump(\&search_like);

Ищите GVGV::GV part в выводе.

...