it-swarm.dev

Perl - Unterprogramm neu definiert

Ich habe diese Frage schon einmal gestellt oder gesucht und gesehen, wie andere gefragt haben - warum erhalte ich die Warnung " Subroutine mySub neu definiert unter ../lib/Common.pm Zeile x "? und Sie erhalten immer die Antwort Sie haben das U-Boot zweimal im selben Code deklariert . Ich habe dieses Testpaket erstellt:

GESAMTE DATEI ---------------

package MyCommonPkg;

use strict;

sub thisSubroutineIsNotDefinedAnywhereElse{
}

1;

GESAMTE DATEI ---------------

und ich benutze dieses Paket aus einem Perl-Skript, das andere Pakete verwendet, die auch dieses Paket verwenden, und erhalte die Warnung: 

Subroutine ThisSubroutineIsNotDefinedAnywhereElse um ../lib/MyCommonPkg.pm Zeile 19 umdefiniert.

Ich verspreche, ich habe dieses U-Boot nirgendwo anders deklariert. Wird dies durch einen Zirkelverweis verursacht? Wie kann ich die Ursache dieser Warnung ermitteln und beheben?

25
user210757

Hast du eine Abhängigkeitsschleife? Wenn Perl Ihr Skript kompiliert und auf eine Zeile wie folgt stößt:

use PackageA;

Perl unterbricht die Kompilierung Ihres Skripts. sucht nach PackageA.pm und beginnt mit der Kompilierung. Wenn es auf eine Zeile wie diese trifft:

use PackageB;

Perl pausiert die Kompilierung von PackageA; sucht nach PackageB.pm und beginnt mit der Kompilierung. Normalerweise würde dies erfolgreich abgeschlossen werden, und Perl würde zurückgehen, um PackageA vollständig zu kompilieren. Wenn dies erfolgreich abgeschlossen wurde, würde das Skript erneut kompiliert werden. Wenn dies erfolgreich abgeschlossen wurde, werden die kompilierten Opcodes ausgeführt.

Jedoch , wenn PackageB.pm diese Zeile enthält:

use PackageA;

Sie könnten davon ausgehen, dass Perl bereits PackageA.pm verarbeitet hat, aber das Problem ist, dass es noch nicht fertig ist. Daher unterbricht Perl die Kompilierung von PackageB und beginnt erneut mit dem Kompilieren von PackageA.pm. Dadurch könnte die Meldung ausgelöst werden, dass Unterprogramme in PackageA neu definiert werden.

In der Regel sollten zwei Pakete nicht beide voneinander abhängig sein. Manchmal ist die Schleife jedoch schwieriger zu finden, da sie durch ein drittes Paket verursacht wird.

34
Grant McLean

Wenn Sie zwei Unterprogramme mit demselben Namen in verschiedenen Paketen haben, sollten Sie diese Warnung (wenn Warnungen aktiviert sind) als "Unterprogramm neu definiert ..." sehen. Der einfache Grund (der sehr nahe an dem ist, was Grant McLean gesagt hat, aber immer noch nicht genau) ist, dass Sie Ihre Pakete die Kompilierungsphase überspringen lassen und sie dann machen müssen. Auf diese Weise findet der Perl-Namespace-Manager zum Zeitpunkt des Kompilierens keine derartigen widersprüchlichen Symbole mit demselben Namen. Wenn Ihre Module keine Fehler enthalten, funktionieren sie auch danach einwandfrei. 

Stellen Sie einfach sicher, dass Sie implementieren 

erfordern Modul;

Anweisung anstatt 

modul verwenden; 

Sie sollten diese Warnung nicht mehr sehen.

24
user1587276

Wenn Sie sich in einem System mit einem Dateisystem ohne Unterscheidung zwischen Groß- und Kleinschreibung (Windows und häufig OSX) befinden und in einer Datei use Common und in einer anderen Datei use common ausführen, können Sie solche Probleme verursachen.

7
hobbs

Das klingt wie ein Problem, das durch zirkuläre Abhängigkeiten verursacht wird. So finden Sie es heraus. Wenn Ihre Problemklasse so aussieht:

package AlientPlanet;
use Dinosaurs;
sub has_dinosaurs {...}
1;

Dann ändern Sie Ihr Beispiel so:

package AlienPlanet;
sub has_dinosaurs {...}     # <-- swap
use Dinosaurs;              # <-- swap
1;

Kompilieren Sie jetzt Ihren Code mit Carp :: Always wie folgt:

⚡ Perl -MCarp::Always -c lib/AlienPlanet.pm                                                                                                            
Subroutine has_dinosaurs redefined at lib/AlienPlanet.pm line 4.
    require AlienPlanet.pm called at lib/Dinosaurs.pm line 4
    Dinosaurs::BEGIN() called at lib/AlienPlanet.pm line 4
    eval {...} called at lib/AlienPlanet.pm line 4
    require Dinosaurs.pm called at lib/AlienPlanet.pm line 5
    AlienPlanet::BEGIN() called at lib/AlienPlanet.pm line 4
    eval {...} called at lib/AlienPlanet.pm line 4
lib/AlienPlanet.pm syntax OK

Nun, da Sie einen Stacktrace haben, können Sie sehen, wo sich die Schleife befindet. Die schnelle und schmutzige Lösung ist die Verwendung von Class :: Load in Dinosaurs.pm.

Für eine ausführlichere Erklärung versuchen Sie meinen Blogbeitrag .

4
Eric Johnson

Führen Sie dieses Programm möglicherweise als CGI-Skript auf einem Webserver aus?

Ich muss den Webserver neu starten, um diese Warnung zu umgehen.

2
Phluks

Schauen Sie sich das Programm package MyCommonPkg.pm an und sehen Sie, was es sagt. Hat es so etwas?

package MyCommonPkg;

use Exporter qw(import);   #  Might be "require" and not "use"
our @EXPORT = qw(thisSubroutineIsNotDefinedAnywhereElse);

Die Syntax kann etwas anders sein. Die wichtigsten Dinge, die Sie sehen sollten, sind die Anweisung package, dass sie Exporter verwendet und dass das Array @EXPORT den Namen Ihrer Unterroutine enthält.

Was passiert, ist ein Namespace-Konflikt. Ihr Paket definiert die gleiche Unterroutine, die Sie definieren.

Um dies zu verhindern, verwendet Perl Namespaces. Standardmäßig lautet Ihr Namespace main. Pakete müssen jedoch mit dem Befehl package ihre eigenen separaten Namensvetter definieren.

Der vollständige Namespace eines Unterprogramms oder einer Variablen ist der Namespace, gefolgt von einem Doppelpunkt, gefolgt vom Namen des Unterprogramms oder der Variablen. Wenn Sie sich beispielsweise File :: Find ansehen, sehen Sie Verweise auf die Variablen $File::Find::name und $File::Find::dir. Dies sind die Variablen $name und $dir im Paket File/Find.pm unter dem Namespace File::Find.

Um Ihnen die Arbeit zu erleichtern, können Pakete export ​​ihre Variablen und Unterroutinen in Ihren main Namespace kopieren. Wenn ich zum Beispiel File :: Copy verwende, kann O dies tun:

...
use File::Copy
...
copy ($file, $to_dir);

Anstatt von:

...
use File::Copy
...
File::Copy::copy ($file, $to_dir);

Wenn Sie sich File/Copy.pm ansehen, sehen Sie Folgendes:

package File::Copy;
...
our(@ISA, @EXPORT, @EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
...
require Exporter;
@ISA = qw(Exporter);
@EXPORT = qw(copy move);

Der package File::Copy; definiert einen Namespace. Mit dem require Exporter; und dem @ISA = qw(Exporter) kann das Paket Unterprogramme und Variablen in den Namespace main exportieren. Der @EXPORT importiert die copy und move -Unterprogramme automatisch in den main -Namensraum - ob du sie willst oder nicht!

Das letzte bisschen ist sehr wichtig. Es wird jetzt als schlechte Manieren angesehen, @EXPORT zu verwenden. Verwenden Sie stattdessen @EXPORT_OK, um die zu verwendenden Unterprogramme aufzulisten. Modernere Pakete wie Scalar :: Util tun dies.

Also mehrere Dinge. Hat Ihr MyCommonPkg eine package MyCommonPkg; -Anweisung? Wenn nicht, sollte es. Dies verhindert, dass die Unterprogramme und Variablen des Pakets Ihr Programm auf unangenehme Weise beeinflussen. Dann können Sie @EXPORT oder @EXPORT_OK verwenden.

Wenn MyCommonPkg eine package -Anweisung hat, wird @EXPORT verwendet? In diesem Fall haben Sie mehrere Möglichkeiten, um dieses Problem zu vermeiden:

  • Ignoriere die Warnung. Es ist nur eine Warnung. Da Sie wissen, dass Sie die Unterroutine neu definieren und Ihre Definition der Unterroutine verwenden möchten, ignorieren Sie sie.

Sie können dies tun, um die Warnung auszuschalten, wenn Sie die Unterroutine neu definieren:

use MyCommonPkg;

no warnings qw(redefine);
sub thisSubroutineIsNotDefinedAnywhereElse {
   ...
}
use warnings qw(redefine);
  • Verwenden Sie require MyCommonPkg; anstelle von use MyCommonPkg;. Dies verhindert das Importieren von Unterroutinen oder Variablen in Ihren Namespace, einschließlich derer, die Sie verwenden wollten. Angenommen, MyCommonPkg definiert vier Unterroutinen: thisSubroutineIsNotDefinedAnywhereElse, foo, bar und barfoo. So verwenden Sie eine dieser Unterroutinen.

Sie müssen dies tun:

my $answer = MyCommonPkg::foo( $input );

Kein Spaß.

  • Verwenden Sie einen anderen Namen für Ihr Unterprogramm. Es sollte dokumentiert worden sein, dass dieses Unterprogramm in MyCommonPkg definiert ist, und wenn Sie MyCommonPkg verwenden möchten, sollten Sie keine exportierten Unterprogrammnamen verwenden.

  • Schließlich, wenn MyCommonPkg ziemlich neu ist und nicht in Dutzenden von Programmen verwendet wird, verwenden Sie @EXPORT_OK anstelle von @EXPORT und stellen Sie sicher, dass alle Programme, die MyCommonPkg verwenden, dies sind geändert, um die gewünschten Unterprogramme zu exportieren:

So was:

use MyCommonPkg qw(foo bar);

In diesem Fall werden nur die Unterprogramme foo und bar exportiert. Die Unterprogramme thisSubroutineIsNotDefinedAnywhereElse und barfoo werden nicht in Ihre Umgebung exportiert.

1
David W.

Stellen Sie sicher, dass Sie diese Zeile am Ende Ihres Moduls nicht vergessen haben: 

1;

Ich weiß, dass es in einigen der Beispiele hier enthalten ist, aber ich erwähne es, weil es leicht zu übersehen ist, und in meinem Fall stellte sich heraus, dass es die einzige Ursache für die Fehler war!

0
todd412

Ich hatte das gleiche Problem. Dies war darauf zurückzuführen, dass das Programm ein Modul verwendete und die Subroutine sowohl im Programm als auch im Perl-Modul vorhanden war.

0
Megiddo

Ich habe versucht, "package Common.pm" als Paketnamen zu verwenden. Der Compiler hat mir Fehler gemacht. Sehr nett von dir? Welche Version von Perl verwendest du? Ich habe es am 5.10.0 und 5.12.1 versucht. 

Auch wenn Sie kompilieren können, sollten Sie die .pm-Datei entfernen. Zum Beispiel;

Datei: some_package.pm;

package some_package;
use strict;

sub yadayadayada { ... }

1;
0
J.J.