CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner: Re: [ChopperCharles] private and protected methods: Edit Log



budman
User

Mar 30, 2012, 7:58 AM


Views: 10004
Re: [ChopperCharles] private and protected methods

The variables $m_Self and $m_LastError would be known as class attributes / variables.

Using 'my' allows fooBar to hide these values from all other subclasses.
In other words, private.

In order to share these with the subclasses,
you need to use 'our' (no longer need to 'use vars', our does this now).


Code
in fooBar.pm: 
our $m_LastError;

in TacoBell.pm:
print $fooBar::m_LastError;


Variables are not inherited. Also, this becomes a maintenance nightmare.
This also breaks the rules of OOP, you are now treating it like a module.

You are getting into data storage now. Again, you should read the perl docs. They cover all of this.

If you want to keep them as class attributes,
then you need to add accessors so the subclasses can access them.


Code
in fooBar: 
sub getLastError {
return $m_LastError;
}

in TacoBell:
print $self->getLastError(),"\n";


This is the preferred method, because you are encapsulating the data, subclasses really shouldn't care about how its stored. Also, you are making your code very maintainable. Future programmers will love you.

There has been a recent change in creating accessors, instead of making a get and set for each attrib, we are now making dual purpose accessor/setor.


Code
sub lastError { 
my $self = shift;
if (@_) {
$self->{"_LAST_ERROR"} = shift;
}
return $self->{"_LAST_ERROR"};
}

in TacoBell:
print $self->lastError(); # get it
$self->lastError("something happened"); # set it


Try to stay away from using class variables/attributes if you can.
You really don't need $m_Self. If objects are blessed, they automatically pass theirs $self as the first arg.

The Error message would be better tied to the object not the class.
I usually limit class attributes to set defaults for the class.
Everything else is in the object. Also, for object vars in the class, I like to use uppercase and a leading underscore as well. Note, if you are using 'use strict', you must quote the hash key if it has a leading underscore.
ex: $self->{"_VAR"} or $self->{'_VAR'}

Lastly, using the class attribute for error message has a bug.
This may look like its working fine now. But.. add a second instance of TacoBell and you now have a very hard to track bug.

I changed fooBar.pm as follows:


Code
sub __foo { #private  
my $name = shift;
if (ref($name)) {
my $self = $name;
unless ( (caller)[0]->isa( ref($self) ) ) {
$self->lastError("Access to private method denied. $_[0]");
$m_LastError = "Access to private method denied. $_[0]";
return -1;
}
$name = shift;
if ( $name =~ /Burr/ ) {
$self->lastError("Weeeee Burrito!");
}
}
print "Hello $name.\n";
return 0;
}

# here is you class attribute accessor
sub GetLastError {
return $m_LastError;
}

# using the object data
sub lastError {
my $self = shift;
if (@_) {
$self->{"_LAST_ERROR"} = shift;
}
return $self->{"_LAST_ERROR"};
}



I added a second instance to test1.pl


Code
print "TacoBell:\n"; 
my $t = TacoBell->new();
$ret_code = $t->iAmfooBar();
if ($ret_code) { print "t->iAmfooBar() failed.\n"; }
$ret_code = $t->__foo("Charles");
if ($ret_code) { print "t->__foo(\"Charles\") failed.\n"; }
$ret_code = $t->burrito();
if ($ret_code) { print "t->burrito() failed.\n"; }
print $t->GetLastError();


print "\nTacoBell2:\n";
my $tb = TacoBell->new();
$ret_code = $tb->iAmfooBar();
if ($ret_code) { print "tb->iAmfooBar() failed.\n"; }
$ret_code = $tb->__foo("Peter");
if ($ret_code) { print "tb->__foo(\"Peter\") failed.\n"; }
print $t->GetLastError(),"\n";
print $t->lastError(),"\n";
print $tb->GetLastError(),"\n";
print $tb->lastError(),"\n";


Output:

Code
TacoBell2: 
Hello fooBar.
tb->__foo("Peter") failed.
Access to private method denied. Peter <--- WRONG
Weeeee Burrito!
Access to private method denied. Peter
Access to private method denied. Peter


The error code for the first instance was overwritten (one object bled into another). The class attribute exists for ALL instances. Remember, when dealing with objects, just because you used 'my' doesn't mean its limited to just that instance.


(This post was edited by budman on Mar 30, 2012, 8:27 AM)


Edit Log:
Post edited by budman (User) on Mar 30, 2012, 8:01 AM
Post edited by budman (User) on Mar 30, 2012, 8:24 AM
Post edited by budman (User) on Mar 30, 2012, 8:27 AM


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives