2009-06-24 2 views
3

Я пишу функцию, которая в основном статична в природе. Я хочу подключить его к Template Toolkit, который проходит по имени класса. В важное значение, она делаетКак я могу написать подпрограмму Perl, которая работает как обычная подпрограмма, так и метод класса?

ClassName->function($args..) 

, но я хочу, чтобы сделать что-то вроде

ClassName::function($args..) 

внутри

sub function { 
} 

, что это правильный способ справиться с обоих случаях?

+0

Почему вы хотите сделать что-то вроде ClassName :: function ($ args ..)? –

+1

Это статический/вспомогательный метод, который действительно не зависит от класса? – Timmy

ответ

7

В общем, нет. a sub либо записывается как метод, либо его нет.

Посмотрите, как File::Spec::Functions обрабатывает эту ситуацию, добавив имя пакета в список аргументов.

Теперь в очень определенном, ограниченном случае, вы можете сделать:

shift if $_[0] eq __PACKAGE__; 

в качестве первой линии в ваших подразделах, чтобы отбросить первый аргумент, когда sub вызываются как метод класса ,

+2

+1. Это становится более безопасным, если каждая из ваших функций принимает фиксированное количество аргументов, и в этом случае вы можете решить, использовался ли синтаксис вызова OO на основе того, есть ли еще один параметр, чем ожидалось. (В его нынешнем виде вызов функции ClassName :: («ClassName»); »вызывает ложное срабатывание.) –

+0

@j_random_hacker Спасибо. –

4

Template Toolkit ожидает, что это плагины для использования OO, поэтому нет способа обеспечить этот интерфейс. Если вам также нужен функциональный интерфейс, у вас есть несколько вариантов.

Perl на самом деле не различает функцию и метод. Основное различие заключается в том, что синтаксис вызова метода неявно включает ссылку на объект (или имя класса, в зависимости от того, как он был вызван) в качестве первого аргумента. Вы можете использовать синтаксис вызова функции и предоставить референт вручную:

ClassName::function('ClassName', @args); 

но это грязно. Более чистым решением было бы разбить его на два субмастера с одной оболочкой для другой. например

package ClassName; 

sub function { 
    # do something 
} 

sub method { 
    my $class = shift; 
    function(@_); 
} 

Эта функция может быть оберткой вокруг метода. Как сказал Синан, File :: Spec делает это, создавая два модуля: один с интерфейсом OO и один с функциональным интерфейсом.

+1

Или пусть Perl сделает для вас обертку: «package ClassName :: Functional; sub AUTOLOAD {no strict refs; ClassName -> $ AUTOLOAD (@_);}" –

+1

@j_random_hacker: нет строгих ссылок не должно быть строгим "refs" или он терпит неудачу под строгими субмаринами :), за исключением того, что он не нужен, потому что -> $ метод разрешен в строгих ссылках. И $ AUTOLOAD полностью квалифицирован, поэтому вам нужен наш $ AUTOLOAD = ~ s /.* :: //; или вы получаете бесконечную рекурсию. – ysth

+0

@ysth: Спасибо! (Так много ошибок в таком маленьком коде, ничего себе ...) Любая идея, почему «-> $ method» разрешен без строгих «refs»? Еще одна произвольная непоследовательность Perl? –

6

Вот безопасный вариант, который сочетает в себе Sinan's и Alan's ответы, а также:

  • Обрабатывает возможность того, что метод вызывается из объекта производного
  • не воспримет ClassName::function("ClassName") как вызов метода

код:

if (@_ == $nArgsExpectedForThisFunc + 1) { 
    $_[0] eq __PACKAGE__ || UNIVERSAL::isa($_[0], __PACKAGE__) || die; 
    shift; 
} 

Для этого требуется, чтобы вы знали количество ожидаемых аргументов; если вы этого не сделаете, но ваш первый аргумент можно отличить от возможных допустимых значений, которые могут быть отправлены, когда он вызывается как метод (например, если ваш первый аргумент должен быть arrayref), тот же общий принцип может быть применен.

+1

+1 Хорошая комбо, но мне также нравится идея обертки Майкла Кармана: http://stackoverflow.com/questions/1038975/perl-function-with-or-without-class/1039085#1039085 –

Смежные вопросы