Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Perl provides no mechanism to hide variables or functions. Although it provides mechanisms such as my() that limit the scope of variables, it does nothing to prevent code from accessing any variable or method that is available and dereferenceable from its current scope.

By convention, packages may indicate that a method or variable is not to be used outside the class by prefixing the method or variable name with an underscore (_) [Conway 2005]. Perl provides no inherent enforcement of this convention; however, it is followed by many modules in CPAN and other developers. This convention must not be violated.

Noncompliant Code Example

This noncompliant code example provides a Car package that registers cars and keeps track of all cars that it creates.

Code Block
bgColor#ffcccc
langperl
{
  package Car;
 
  my %_all_cars;
 
  sub new {
    my ($class, $type) = @_;
    my $self = {type=>$type};
    bless $self, $class;
    $_all_cars{$self} = 1;
    return $self;
  };
 
  sub DESTROY {
    delete $_all_cars{shift()};
  };
 
  sub type {
    my $self = shift;
    return $$self{type};
  }
 
  sub _get_all_cars {
    return %_all_cars;
  }
}


my $mine = Car->new("Transam");
my $type = $mine->type();
print "I drive a $type.\n";
my $yours = Car->new("Corvette");
$type = $yours->type();
print "You drive a $type.\n";

my %cars = Car::_get_all_cars();
my @all = keys( %cars);
my $count = $#all + 1;
print "There are $count cars on the road.\n";

This program behaves as expected, correctly reporting 2 cars on the road. However, it clearly violates encapsulation, because the _get_all_cars() method is considered private within the Car class.

Compliant Solution

This compliant solution adds a public method and invokes it instead of any private method.

Code Block
bgColor#ccccff
langperl
{
  package Car;

  my %_all_cars;

  sub count_cars {
    my @all = keys( %_all_cars);
    return 1 + $#all;
  }

  # ... other methods of Car
}

# ...
my $count = Car::count_cars();
print "There are $count cars on the road.\n";

Exceptions

OOP31:EX0: A class may access private subroutines in classes it is inherited from.

OOP31:EX1: This rule does not apply to classes or modules that do not obey this convention. For instance, the POSIX package provides an API to the system calls endorsed by the POSIX standard. Many of these calls begin with _ but are not meant to be private.

Risk Assessment

Using deprecated or obsolete classes or methods in program code can lead to erroneous behavior.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

OOP31-PL

Medium

Probable

Medium

P8

L2

Automated Detection

Tool

Diagnostic

Perl::Critic

 

Subroutines::ProtectPrivateSubs

Variables::ProtectPrivateVars

Bibliography