Let's say we have an object we
want to be able to
access anywhere in the code, without making it a global variable or
passing it as an argument to functions. The singleton design pattern
helps here. Rather
than
implementing this pattern from scratch, we will use
Class::Singleton.
For example, if we have a class Book::DBIHandle
that returns an instance of the opened database connection handle, we
can use it in the TransHandler
phase's handler (see Example A-6).
Example A-6. Book/TransHandler.pm
package Book::TransHandler;
use Book::DBIHandle;
use Apache::Constants qw(:common);
sub handler {
my $r = shift;
my $dbh = Book::DBIHandle->instance->dbh;
$dbh->do("show tables");
# ...
return OK;
}
1;
We can then use the same database handle in the content-generation
phase (see Example A-7).
Example A-7. Book/ContentHandler.pm
package Book::ContentHandler;
use Book::DBIHandle;
use Apache::Constants qw(:common);
sub handler {
my $r = shift;
my $dbh = Book::DBIHandle->instance->dbh;
$dbh->do("select from foo...");
# ...
return OK;
}
1;
In httpd.conf, use the following setup for the
TransHandler and content-generation phases:
This specifies that Book::TransHandlershould be
used as the PerlTransHandler, and
Book::ContentHandlershould be used as a
content-generation handler. We use the + prefix to
preload both modules at server startup, in order to improve memory
sharing between the processes (as explained in Chapter 10).
Book::DBIHandle, shown in Example A-8, is a simple subclass of
Class::Singleton that is used by both handlers.
Example A-8. Book/DBIHandle.pm
package Book::DBIHandle;
use strict;
use warnings;
use DBI;
use Class::Singleton;
@Book::DBIHandle::ISA = qw(Class::Singleton);
sub _new_instance {
my($class, $args) = @_;
my $self = DBI->connect($args->{dsn}, $args->{user},
$args->{passwd}, $args->{options})
or die "Cannot connect to database: $DBI::errstr";
return bless $self, $class;
}
sub dbh {
my $self = shift;
return $$self;
}
1;
Book::DBIHandle inherits the instance(
) method from Class::Singleton and
overrides its _new_instance( ) method.
_new_instance( ) accepts the connect(
) arguments and opens the connection using these arguments.
The _new_instance( ) method will be called only
the first time the instance( ) method is called.
We have used a reference to a scalar ($dbh) for
the Book::DBIHandle objects. Therefore, we need to
dereference the objects when we want to access the database handle in
the code. The dbh( ) method does this for us.
Since each child process must have a unique database connection, we
initialize the database handle during the
PerlChildInit phase, similar to
DBI::connect_on_init( ). See Example A-9.
Example A-9. Book/ChildInitHandler.pm
package Book::ChildInitHandler;
use strict;
use Book::DBIHandle;
use Apache;
sub handler {
my $s = Apache->server;
my $dbh = Book::DBIHandle->instance(
{ dsn => $s->dir_config('DATABASE_DSN'),
user => $s->dir_config('DATABASE_USER'),
passwd => $s->dir_config('DATABASE_PASSWD'),
options => {
AutoCommit => 0,
RaiseError => 1,
PrintError => 0,
ChopBlanks => 1,
},
}
);
$s->log_error("$$: Book::DBIHandle object allocated, handle=$dbh");
}
1;
Here, the instance( ) method is called for the
first time, so its arguments are passed to the new
_new_instance( ) method. _new_instance(
) initializes the database connection.
httpd.conf needs to be adjusted to enable the
new ChildInitHandler: