Pull to refresh

Корректное использование AUTOLOAD

Reading time1 min
Views4.2K
Хотелось бы сразу предупредить: Это статья предназначена не для зубров, а описывает вполне обычный трюк с AUTOLOAD.

Введение



В Perl существует замечательная возможность отрабатывать вызовы к неопределённым методам.

Например, в случае
package Something;

our $AUTOLOAD;

sub AUTOLOAD
{
  return 'any data';
}

sub DESTROY
{
}

package  XTest;

my $o = new Something();

print $o->dry();


Результат будет равен 'any data'.

Недостатки



Недостаток у этого способа фактически один — низкая производительность при повторных вызовах.

Генерация методов на лету



Исправит это поведение генерация методов на лету.

package Something;

our $AUTOLOAD;

sub AUTOLOAD
{
  my ($self) = @_;  
  my $name = $AUTOLOAD;
  return if $name =~ /^.*::[A-Z]+$/;
  $name =~ s/^.*:://;   # strip fully-qualified portion
  my $sub = sub
  {
    my $self = shift();
    return 'any data';
  };
  no strict 'refs';
  *{$AUTOLOAD} = $sub;
  use strict 'refs';
  goto &{$sub};
}

package  XTest;

my $o = new Something();

print $o->dry();


Где это полезно



Помимо разного рода кастомных акцессоров (я искренне рекомендую Class::Accessor::Fast, где возможно), очень часто полезно для написания врапперов, вокруг обьектов, от которых нельзя отнаследоваться (например, нужен хэш, а обьект является хэндлом XS).

Производительность



Судя по пакету Benchmark, создание обьекта и 100-кратный вызов неизвестного метода на сервере (FreeBSD/x64/Perl5.8.8) даёт в первом случае до 3400 вызовов в секунду, и до 11000 вызовов в секунду во втором случае. Скорость вырастает втрое.
Tags:
Hubs:
+2
Comments12

Articles