Jak mogę dynamicznie dołączać Moduły Perla bez użycia eval?
Muszę dynamicznie dołączyć moduł Perla, ale jeśli to możliwe, chciałbym trzymać się z dala od evalu ze względu na Robocze standardy kodowania. To działa:
$module = "My::module";
eval("use $module;");
Ale potrzebuję sposobu, aby to zrobić bez eval
jeśli to możliwe. Wszystkie wyszukiwania google prowadzą do metody eval
, ale żadne w inny sposób.
Czy można to zrobić bez eval
?
6 answers
Użycie require
aby załadować Moduły w czasie wykonywania. Często dobrym pomysłem jest zawinięcie tego w blok (Nie łańcuch) eval
na wypadek, gdyby moduł nie mógł zostać załadowany.
eval {
require My::Module;
My::Module->import();
1;
} or do {
my $error = $@;
# Module load failed. You could recover, try loading
# an alternate module, die with $error...
# whatever's appropriate
};
Powodem składni eval {...} or do {...}
i tworzenia kopii $@
jest to, że $@
jest zmienną globalną, która może być ustawiona przez wiele różnych rzeczy. Chcesz pobrać wartość tak atomicznie, jak to możliwe, aby uniknąć stanu wyścigu, w którym coś innego ustawiło ją na inną wartość.
Jeśli nie znasz nazwy modułu do czasu uruchomienia będziesz musiał ręcznie tłumaczyć nazwę modułu (My::Module) i nazwę pliku (My/Module.pm):
my $module = 'My::Module';
eval {
(my $file = $module) =~ s|::|/|g;
require $file . '.pm';
$module->import();
1;
} or do {
my $error = $@;
# ...
};
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-16 20:58:26
Może skorzystasz z modułu podstawowego Module:: Load
Z twoim przykładem:
use Module::Load;
my $module = "My::module";
load $module;
"Module:: Load-Runtime require of both modules and files"
"load eliminuje potrzebę wiedzieć, czy próbujesz wymagać pliku lub modułu."
Jeśli się nie powiedzie, umrze z czymś podobnym " nie można zlokalizować xxx w @INC (@INC zawiera: ...".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-01 14:46:52
Cóż, zawsze jest require
jak w
require 'My/Module.pm';
My::Module->import();
Zauważ, że tracisz wszelkie efekty, które możesz uzyskać z wywołania import
w czasie kompilacji zamiast trybu runtime.
Edit: kompromis pomiędzy tą A eval jest następujący: eval pozwala na użycie zwykłej składni modułu i daje bardziej wyraźny błąd, jeśli nazwa modułu jest nieprawidłowa (w przeciwieństwie do zwykłego Nie odnalezionego). OTOH, sposób ewaluacji jest (potencjalnie) bardziej uzależniony od arbitralnego wtrysku kodu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-16 20:15:35
nie, nie jest możliwe Bez eval
, ponieważ require()
wymaga nazwy modułu bareword, jak opisano w perldoc-f require. Jednak nie jest to złe użycie eval, ponieważ nie pozwala na wstrzyknięcie dowolnego kodu(zakładając, że masz kontrolę nad zawartością pliku, którym jesteś require
ing, oczywiście).
EDIT: Kod poprawiony poniżej, ale zostawiam pierwszą wersję dla kompletności.
używam używałam tego małego cukru moduł do wykonywania obciążeń dynamicznych w czasie pracy:
package MyApp::Util::RequireClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);
# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
my ($class) = @_;
eval "require $class" or do { die "Ack, can't load $class: $@" };
}
1;
PS. Wpatruję się w tę definicję (pisałem ją już jakiś czas temu) i zastanawiam się nad dodaniem tej:
$class->export_to_level(1, undef, @imports);
... to powinno działać, ale nie jest testowane.
EDIT : Wersja 2 teraz, dużo ładniejsza bez ewaluacji (dzięki ysth)::)
package MyApp::Util::RequireClass;
use strict;
use warnings;
use Exporter 'import'; # gives you Exporter's import() method directly
our @EXPORT_OK = qw(requireClass);
# Usage: requireClass(moduleName);
# does not do imports (wrong scope) -- you should do this after calling me: $class->import(@imports);
sub requireClass
{
my ($class) = @_;
(my $file = $class) =~ s|::|/|g;
$file .= '.pm';
require $file; # will die if there was an error
}
1;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-16 21:20:10
Class:: MOP na CPAN ma do tego metodę load_class: http://metacpan.org/pod/Class::MOP
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-05 20:55:13
Lubię robić takie rzeczy..
require Win32::Console::ANSI if ( $^O eq "MSWin32" );
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-06 23:31:59