SoFunction
Updated on 2025-04-14

Perl5 OOP study notes


Copy the codeThe code is as follows:

#
package MyClass;

sub new {
my $this = {};
bless($this);
}

package main;

my $obj1 = MyClass::new();
my $obj2 = MyClass->new();
my $obj3 = new MyClass();

print(join("\n", ref($obj1), ref($obj2), ref($obj3)));

__END__
MyClass
MyClass
MyClass

Note that the effect of new MyClass() above is the same as that of MyClass->new(). Here new is not a keyword, but a function name. Similarly, if there is a foo member function, you can also foo MyClass(args), which is actually MyClass::foo(MyClass, args);

Having said that, what if you need to initialize object data? As mentioned earlier, object data is stored in the referenced data itself, so we usually refer to a Hash to bless as an object. So we often see new calls like this:
Copy the codeThe code is as follows:

my $obj = MyClass->new('key1' => 'value1', 'key2' => 'value2');

or
Copy the codeThe code is as follows:

my $obj = MyClass->new({'key1' => 'value1', 'key2' => 'value2'});

The difference between the two calling methods is that the processing in the new function is different, because the former passes in a Hash entity, while the latter passes in a Hash reference. To be compatible with both cases, the new function is usually written like the following program:
Copy the codeThe code is as follows:

#
package MyClass;

sub new {
my $class = shift();
my $this = ref(@_[0]) ? @_[0] : {@_};
bless($this);
}

package main;
use Data::Dumper;

my $obj1 = MyClass->new('name' => 'James Fancy', 'age' => 30);
my $obj2 = MyClass->new({'name' => 'James Fancy', 'age' => 30});

print(Dumper($obj1));
print(Dumper($obj2));

__END__
$VAR1 = bless( {
'name' => 'James Fancy',
'age' => 30
}, 'MyClass' );
$VAR1 = bless( {
'name' => 'James Fancy',
'age' => 30
}, 'MyClass' );

Access object data
Since the Hash reference is usually blessed into an object, then this is the case.
Since it is a Hash reference, the easiest way to access data is the same as accessing a Hash reference. for example
Copy the codeThe code is as follows:

$obj->{'name'} = "You Name";
my $name = $obj->{'name'};
$obj->{'name'} = "You Name";
my $name = $obj->{'name'};

If you want to write less curly braces, you can solve it by defining setter/getter. Because getters and setters can be distinguished based on whether there are any parameters, it is possible to merge them in a function, such as the following name function
Copy the codeThe code is as follows:

#
package MyClass;
sub new {
my $class = shift();
my $this = ref(@_[0]) ? @_[0] : {@_};
bless($this);
}
sub name {
my $this = shift();
if (@_[0]) {
$this->{'name'} = @_[0];
}
return $this->{'name'};
}
package main;
my $obj = MyClass->new('name' => 'James Fancy');
print($obj->name, "\n");
print($obj->name("New Name"), "\n");
__END__
James Fancy
New Name
#
package MyClass;
sub new {
my $class = shift();
my $this = ref(@_[0]) ? @_[0] : {@_};
bless($this);
}
sub name {
my $this = shift();
if (@_[0]) {
$this->{'name'} = @_[0];
}
return $this->{'name'};
}
package main;
my $obj = MyClass->new('name' => 'James Fancy');
print($obj->name, "\n");
print($obj->name("New Name"), "\n");
__END__
James Fancy
New Name

Using setter/getter can indeed make the program look much simpler. However, it is still very tiring to write a getter/setter for each data in the object. So, the AUTOLOAD function was lifted out and take a look at the following program
Copy the codeThe code is as follows:

package MyClass;

sub new {
my $class = shift();
my $this = ref(@_[0]) ? @_[0] : {@_};
bless($this, $class);
}

sub AUTOLOAD {
my $this = $_[0];
if (!ref($this)) {
return;
}

my $name = $AUTOLOAD;

if (defined($name)) {
$name =~ s/.*:://;
} else {
return;
}

my $class = ref($this);
if (defined($this->{$name}) || @_) {
no strict 'refs';
*{"${class}::$name"} = sub {
my $this = shift();
$this->{$name} = shift() if (@_);

# make a property in hash reference type to HashObject object.
if (ref($this->{$name}) eq 'HASH') {
bless($this->{$name}, $class);
}

return $this->{$name};
};

goto &$name;
}
}

package main;

my $obj = MyClass->new('name' => 'James Fancy');
$obj->more1({'key', 'value of more1->key'});
print($obj->name, "\n");
print($obj->more1->key, "\n");
print($obj->more2({})->key("value of more2->key"), "\n");

__END__
James Fancy
value of more1->key
value of more2->key

Isn't it much more convenient to call this way? But AUTOLOAD is very tiring to write. If you only need one data object, there is a class with Hash::AsObject on the Internet that is very useful, and the usage is similar to the last example above.
inherit
I really haven't studied the inheritance much. However, simple inheritance is probably just using the use base statement to introduce the base class, for example
Copy the codeThe code is as follows:

package Parent;

sub test1 {
print("Parnet::test1\n");
}

sub test {
print("Parent::test\n");
}

package Sub;
use base Parent;

sub test {
print("Sub::test\n");
}

sub test2 {
$_[0]->Parent::test();
}

package main;

my $obj = bless({}, *Sub);
$obj->test();
$obj->test1();
$obj->test2();

__END__
Sub::test
Parnet::test1
Parent::test


References

Published by Southeast University Press, O'Reilly's "Proficient in Perl (Photocopy Edition)", by Brian D Foy
Perl version 5.10.0 documentation,/
Hash::AsObject source code, from/~nkuitse/Hash-AsObject-0.11/lib/Hash/