Question

i am switching my application from Perl 5.8.8 to Perl 5.16.3 and now i get tons of warnings about the following third party code in SOAP::Lite

unless (defined %{"$protocol_class\::Client::" )

The code produces the following warings:

Warning in Perl code: \t(Maybe you should just omit the defined()?)
Warning in Perl code: defined(%hash) is deprecated at /.../SOAP/Lite.pm
line ...

If i reduce it to a simple example it looks like

unless( defined %{"some::string"} )

Question: Why should someone interpret a string "some::string" as a hash %{"some::string"} and check if the hash is defined? It doen't make any sense to me. I want to replace this codepiece with something else without breaking the third party module so i can focus on real important warnings and errors.

Here is the whole function. I don't know if this helps because think its some kind of Guru code which is a little bit hard to understand

sub proxy {
    my $self = shift;
    $self = $self->new() if not ref $self;

    my $class = ref $self;

    return $self->{_proxy} unless @_;

    $_[0] =~ /^(\w+):/ or die "proxy: transport protocol not specified\n";
    my $protocol = uc "$1"; # untainted now

    # HTTPS is handled by HTTP class
    $protocol =~s/^HTTPS$/HTTP/;

    (my $protocol_class = "${class}::$protocol") =~ s/-/_/g;

    no strict 'refs';
    unless (defined %{"$protocol_class\::Client::"}
        && UNIVERSAL::can("$protocol_class\::Client" => 'new')
    ) {
        eval "require $protocol_class";
        die "Unsupported protocol '$protocol'\n"
            if $@ =~ m!^Can\'t locate SOAP/Transport/!;
        die if $@;
    }

    $protocol_class .= "::Client";
    return $self->{_proxy} = $protocol_class->new(endpoint => shift, @_);
}
Was it helpful?

Solution

The construct %Package:: gives access to a package's stash, i.e. the symbol table hash.

All this code is doing is checking whether a given package has been loaded (in which case its stash will exist) and that there is a new method for the package. If not then require is used to load the module.

The call to UNIVERSAL::can('package', 'method') is normally written as 'package'->can('method') and you can change that here if you like, but the code will work as it stands.

I suggest you do just as the warnings say, and omit the defined. It would also be nicer if you put the package name in its own variable instead of using the interpolated double-quoted string twice, and you can use the conventional call to can as I have described. It would look like this

my $package = "${protocol_class}::Client";
unless ( %{"${package}::"} and $package->can('new') ) {

  # load missing module
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top