Another way if you want to keep it a function, which will prevent it from being accessible outside of your class, or if you want to export it as a function if your module also provides non-OO functionality:
package Foo;
use warnings;
use strict;
use Exporter qw(import);
our @EXPORT_OK = qw(function_or_method);
our %EXPORT_TAGS = (all => [@EXPORT_OK]);
sub new {
return bless {}, shift;
}
sub function_or_method {
# Throw away the first param if:
# A) it's defined, and
# B) it's either the class, or an object of the class
if (defined $_[0]) {
shift if $_[0] eq __PACKAGE__ || ref $_[0] eq __PACKAGE__;
}
# Now we grab the remaining params (if expecting any)
my ($call_num, $call_type) = @_;
print "Num: $call_num called as $call_type\n";
}
The calling script:
use warnings;
use strict;
use lib '.';
use Foo qw(:all);
# Call as function
function_or_method('1', 'function');
# Call as method
my $obj = Foo->new;
$obj->function_or_method('2', 'method');
Note that if you shift off the object to use the symbol as a function only, you obviously can't retrieve any of the object's attributes or call its other methods unless 1) you have stored a saved object globally (ie. at the class scope) or 2) you pass in an object through explicit parameter passing.
Sometimes I provide my users the option of an OO interface or functional interface for an entire class. Again, if used in non-OO context, you can't call things on $self within the module. My entire WiringPi::API (source) is one such distribution that is 100% OO capable, and 100% functional capable.