isevcik
isevcik

Reputation: 583

How to globally override method in Perl

I am forced to use old version of Apache2::Cookie class which contains bug in method fetch(). I tried to override method in startup script, but it doesn't work later in other modules than startup script:

local *Apache2::Cookie::fetch = sub { ... }

How to override method globally for all other modules?

Upvotes: 1

Views: 376

Answers (1)

simbabque
simbabque

Reputation: 54333

As Sobrique pointed out in their comment, the local is definitely an issue. But not the only one.

You need to load the pacakge first before you do this. Perl will take the last definition of the sub, just like the last assigned value will be the value of a variable.

my $foo;
$foo = 1;
$foo = 3;
print $foo; # 3, obviously

The same goes for your overwriting.

*Apache2::Cookie::fetch = sub { ... }; # note ... is valid syntax
require 'foo';

$cookie = Apache2::Cookie->new; # not sure if that is correct

# in foo.pm
use Apache2::Cokie; # this will overwrite your implementation

Loading modules in Perl works with %INC, a super-global hash that keeps track of which files have been loaded. If you use a file twice, it only gets loaded and parsed the first time. The second time, it will only call import on the package.

So the trick is to load Apache2::Cookie first, so it's already parsed when the real code loads it again.

use Apache2::Cookie;
BEGIN {
  *Apache2::Cookie::fetch = sub { ... };
}
require 'foo'; # or use, no matter

$cookie = Apache2::Cookie->new; # not sure if that is correct

# in foo.pm
use Apache2::Cokie; # now this won't overwrite your implementation

Now Perl already has the file loaded, and the package installed in its guts. Then you overwrite the sub. Then it gets not loaded again and your fix is still intact when it gets called.

Upvotes: 4

Related Questions