Reputation: 3106
Background: I am new to Perl and I am tinkering with a simple script that loops through a hash value that is an anonymous array.
The Issue I cannot seem to loop through the array. All I get is ARRAY(0x1663b78)
The Code
#!/usr/bin/perl
package Foo;
use strict "vars";
sub new {
my $class = shift;
my $self = {
distro => "",
pkg_mgr => "",
options => ["PHP + Apache", "PHP + Lighthttpd", "PHP + Nginx", "RubyGems + Rails", "Node JS + NPM"]
};
bless $self, $class;
return $self;
}
sub print_options {
my($self) = @_;
foreach($self->{options}) {
print $_ . "\n";
}
}
my $setup = new Foo();
$setup->print_options();
Also, if someone could kindly inform me if it's remotely useful to use use strict "vars";
if I really have no need for private or public variables. I know how I would do this in PHP but I can't wrap my head around this in Perl.
Lastly, my reason for using Perl is because eventually I'm going to make an application that installs software for servers (including PHP). This script will require user interaction via command line.
Upvotes: 3
Views: 2606
Reputation: 107080
A few little Perl clues:
Data::Dumper
will help you understand the structure.main
package. You should flip your program around. The last two statements should be on the top, and define your package below.If you used Data::Dumper
and dumped the data of $self
when you called it, you would realize that $self
is a hash with three keys, and that the options
key is pointing to an anonymous array.
In order to do what you want, you have to dereference that anonymous array:
sub print_options {
my($self) = @_;
for ( @{$self->{options} } ) {
print $_ . "\n";
}
}
However, let's clean up your program to make it a complete class. First, methods never print -- they return values. Thus, you should not have a print_options
method. Instead, it should return the array (or a reference to an array).
Also, your constructor doesn't have to know how your Options
are structured. What if you change it? Let's look at a changed program:
#! /usr/bin/env perl
#
use warnings;
use strict;
use feature qw(say);
my $setup = Foo->new;
for my $option ( $setup->Option ) {
say $option;
}
package Foo;
sub new {
my $class = shift;
my $self = {};
bless $self, $class;
$self->Option("PHP + Apache");
$self->Option("PHP + Lighthttpd");
$self->Option("PHP + Nginx");
$self->Option("RubyGems + Rails");
$self->Option("Node JS + NPM");
return $self;
}
sub Distro {
my $self = shift;
my $distro = shift;
if ( defined $distro ) {
$self->{DISTRO} = $distro;
}
return $self->{DISTRO};
}
sub Package_Manager {
my $self = shift;
my $package = shift;
if ( defined $package ) {
$self->{PACKAGE} = $package;
}
return $self->{PACKAGE};
}
sub Option {
my $self = shift;
my $option = shift;;
if ( not exists $self->{OPTION} ) {
$self->{OPTION} = [];
}
if ( defined $option ) {
push @{ $self->{OPTION} }, $option;
}
my @array = @{ $self->{OPTION} };
return wantarray ? @array : \@array;
}
First, unlike PHP, Perl compiles the code before execution. Thus, you can define packages and their subroutine on the bottom of the program. The few lines of code above operation in the default main package. If I did use a package variable in my Foo
package, I wouldn't accidentally be using it in my program.
Notice that none of my methods or my constructor know about the structure of the Foo
object. When I set my options in my new
constructor, I call my Option
method to do the setting. This way, if I change the way I store my options, I only have to change my Option
method and not worry where else in my package it has to be changed. It also simplifies my program and makes it easier to support.
By making my Option
method to either set or get my options, I simplify the code. I can see that I'm storing options in an anonymous array, and it's obvious that I need to dereference it when I return the object. I like using wantarray
and giving the user the option whether they want an array or a reference to an array.
Notice that I don't simply return $self->{OPTION}
. It is a reference to an array and should have worked, but if I return that, I'm returning the memory location of that object! Thus, if a user changes that reference, they're changing my object without going through my methods. Thus, I make another array, and return a reference to that. Muck with that array reference all you want, you're not changing my object.
This code isn't complete. I can set options, but not unset options. It may be nice to have a way to push and pop options. Instead, all you can do at this point is return the entire list, and not modify it.
Upvotes: 9
Reputation: 6798
$self->{options}
is not an array but a reference to an array. You need to de-reference it to be able to iterate through its values.
my @options = @{ $self=>{options} };
Upvotes: 4
Reputation: 31962
You need to do the below change.
foreach(@{$self->{options}}) {
^^ ^
options
is the key to an arrayref
and you need to de-reference it to use it.
As to your other question, a more general pair of pragmas are recommended, especially for beginners
use strict;
use warnings;
Upvotes: 1