| home / programming / perl / mod_perl / chap6 / 1 | [previous] |
|
|
The following solution should be used only as a short term bandage.
You can force reloading of the modules either by fiddling with %INC
or by replacing use( ) and require(
) calls with do( ).
If you delete the module entry from the %INC
hash before calling require( ) or use(
), the module will be loaded and compiled again. See Example 6-13.
Example 6-13: project/runA.pl
BEGIN {delete $INC{"MyConfig.pm"};}use lib qw(.);use MyConfig;print "Content-type: text/plain\n\n";print "Script A\n";print "Inside project: ", project_name( );
Apply the same fix to runB.pl.
Another alternative is to force module reload via do(
), as seen in Example 6-14.
Example 6-14: project/runA.pl forcing module reload by using do() instead of use()
use lib qw(.);do "MyConfig.pm";print "Content-type: text/plain\n\n";print "Script B\n";print "Inside project: ", project_name( );
Apply the same fix to runB.pl.
If you needed to import( ) something
from the loaded module, call the import( ) method
explicitly. For example, if you had:
use MyConfig qw(foo bar);
now the code will look like:
do "MyConfig.pm";MyConfig->import(qw(foo bar));
Both presented solutions are ultimately ineffective, since the modules in question will be reloaded on each request, slowing down the response times. Therefore, use these only when a very quick fix is needed, and make sure to replace the hack with one of the more robust solutions discussed in the following sections.
The first faulty scenario can be solved by placing library modules in a subdirectory structure so that they have different path prefixes. The new filesystem layout will be:
projectA/ProjectA/MyConfig.pmprojectA/run.plprojectB/ProjectB/MyConfig.pmprojectB/run.pl
The run.pl scripts will need to be modified accordingly:
use ProjectA::MyConfig;
and:
use ProjectB::MyConfig;
However, if later on we want to add a new script to either of these projects, we will hit the problem described by the second problematic scenario, so this is only half a solution.
Another approach is to use a full path to the script, so the latter
will be used as a key in %INC:
require "/home/httpd/perl/project/MyConfig.pm";
With this solution, we solve both problems but lose some portability. Every time a project moves in the filesystem, the path must be adjusted. This makes it impossible to use such code under version control in multiple-developer environments, since each developer might want to place the code in a different absolute directory.
This solution makes use of package-name declaration in the require(
)d modules. For example:
package ProjectA::Config;
Similarly, for ProjectB, the package
name would be ProjectB::Config.
Each package name should be unique in relation to the other packages
used on the same httpd server. %INC
will then use the unique package name for the key instead of the filename of
the module. It's a good idea to use at least two-part package names for your
private modules (e.g., MyProject::Carp instead
of just Carp), since the latter will collide with
an existing standard package. Even though a package with the same name may not
exist in the standard distribution now, in a later distribution one may come
along that collides with a name you've chosen.
What are the implications of package declarations? Without package
declarations in the modules, it is very convenient to use(
) and require( ), since all variables and
subroutines from the loaded modules will reside in the same package as the script
itself. Any of them can be used as if it was defined in the same scope as the
script itself. The downside of this approach is that a variable in a module
might conflict with a variable in the main script; this can lead to hard-to-find
bugs.
With package declarations in the modules, things are a bit more
complicated. Given that the package name is PackageA,
the syntax PackageA::project_name( ) should be
used to call a subroutine project_name( ) from
the code using this package. Before the package declaration was added, we could
just call project_name( ). Similarly, a global
variable $foo must now be referred to as $PackageA::foo,
rather than simply as $foo. Lexically defined variables
(declared with my( )) inside the file containing
PackageA will be inaccessible from outside the
package.
You can still use the unqualified names of global variables and subroutines if these are imported into the namespace of the code that needs them. For example:
use MyPackage qw(:mysubs sub_b $var1 :myvars);
Modules can export any global symbols, but usually only subroutines
and global variables are exported. Note that this method has the disadvantage
of consuming more memory. See the perldoc Exporter
manpage for information about exporting other variables and symbols.
Let's rewrite the second scenario in a truly clean way. This is how the files reside on the filesystem, relative to the directory /home/httpd/perl:
project/MyProject/Config.pmproject/runA.plproject/runB.pl
Examples 6-15, 6-16, and 6-17 show how the code will look.
Example 6-15: project/MyProject/Config.pm
package MyProject::Configsub project_name { return 'Super Project'; }1;
Example 6-16: project/runB.pl
use lib qw(.);use MyProject::Config;print "Content-type: text/plain\n\n";print "Script B\n";print "Inside project: ", MyProject::Config::project_name( );
Example 6-17: project/runA.pl
use lib qw(.);use MyProject::Config;print "Content-type: text/plain\n\n";print "Script A\n";print "Inside project: ", MyProject::Config::project_name( );
As you can see, we have created the MyProject/Config.pm file and added a package declaration at the top of it:
package MyProject::Config
Now both scripts load this module and access the module's subroutine,
project_name( ), with a fully qualified name, MyProject::Config::project_name(
).
See also the perlmodlib and perlmod manpages.
From the above discussion, it also should be clear that you cannot
run development and production versions of the tools using the same Apache server.
You have to run a dedicated server for each environment. If you need to run
more than one development environment on the same server, you can use Apache::PerlVINC,
as explained in Appendix B.
| home / programming / perl / mod_perl / chap6 / 1 | [previous] |
Created: March 11, 2003
Revised: July 23, 2003
URL: http://webreference.com/programming/perl/mod_perl/chap6/1