2009-04-26 7 views
7

Supponiamo di avere un'applicazione ENORME "develoopped";) da parte di una grande squadra. Ecco un modello semplificato del potenziale disastro che può verificarsi quando qualcuno controlla troppo in profondità in una struttura dati. Se non è possibile disabilitare completamente l'autovificazione o nell'ambito, come aggirare questo problema? Grazie mille :) !!!!Come disabilitare l'autovivificazione in Perl?

use strict; use warnings;use Data::Dumper; 

my $some_ref = {akey=>{deeper=>1}}; 
print Dumper($some_ref); 
if($some_ref->{deep}{doot} == 1){ 
    print 'too deep '.$/; 
} 

if($some_ref->{deep}){ 
    print 'Already in a deep doot'.$/; 
} 

print Dumper($some_ref); 

Emette i seguenti:

$VAR1 = { 
      'akey' => { 
         'deeper' => 1 
        } 
     }; 
Use of uninitialized value in numeric eq (==) at autovivify_test.pl line 5. 
Already in a deep doot 
$VAR1 = { 
      'deep' => {}, 
      'akey' => { 
         'deeper' => 1 
        } 
     }; 

Sì so che c'è un avvertimento, ma ... potrebbe essere troppo tardi.

Hey ragazzi potrebbe essere d'aiuto dire che il mio hashref fa riferimento a un HASH legato.

Può essere se implemento un buon metodo FETCH che controlla i controlli più in profondità nella struttura, risolverò facilmente il mio problema?


ho guardato Tie::StrictHash, Tie::Hash e perltie. versione Qui è semplificata della mia soluzione:

#!/usr/bin/env perl; 
#test_tie.pl 

package StrictHash; 
use strict; use warnings; 
use Tie::Hash; 
our @ISA = qw(Tie::StdHash); 
use Carp; 

sub TIEHASH { 
    my $class = shift; 
    my $hash = bless {@_}, $class; 
    return $hash; 
} 
##======================================================================== 
## FETCH fails if applied to a member that doesn't exist. 
##======================================================================== 
sub FETCH { 
    my ($hash, $key) = @_; 
    Carp::confess "key '$key' does not exist" unless exists $hash->{$key}; 
    return $hash->{$key}; 
} 
##======================================================================== 
package main; 
use strict;use warnings;use Data::Dumper; 
#Imagine StrictHash is in ./StrictHash.pm 
#use StrictHash; 
my %hash; 
tie %hash, 'StrictHash', akey => {deeper=>1} ; 

my $some_ref =\%hash; 
print Dumper($some_ref); 
if($some_ref->{deep}{doot} == 1){ 
    print 'too deep '.$/; 
} 

quello che ho fatto è quello di toccare un solo posto in app. Ora tutti i Luoghi come if ($ some_ref -> {deep} {doot}) causeranno la morte con stack-trace. Quindi li troverò facilmente e li correggerò. E nuovi scritti di questo tipo NON saranno possibili. Perl va bene anche per le grandi app, devi solo saperne di più;).

Grazie a tutti! Spero che questo aiuti anche gli altri.

+0

qual è la tua domanda? –

+0

Come disabilitare l'autovivificazione in perl? –

risposta

15

È possibile utilizzare un oggetto anziché l'hash (vedere Moose) o utilizzare uno strict tied hash. Oppure si può trasformare gli avvisi in errori, se si vuole veramente:

use warnings NONFATAL => 'all', FATAL => 'uninitialized'; 
+1

+1, FATAL su non inizializzato per la vittoria. –

+0

Può essere, come dice Kent, usa avvertimenti NONFATAL => 'all', FATAL => 'non inizializzato'; è il modo più accettabile per andare. Potrei avere questo set up in sviluppo. Lascerò la domanda per un po 'di più, solo per vedere se qualcuno suggerirà qualcosa di ancora più intelligente :). Grazie. –

+0

Mi sono appena reso conto che ho bisogno di scrivere solo un po 'di controllo nel mio metodo FETCH poiché il mio riferimento punta a un HASH Tied in realtà. Grazie davvero molto. –

9

È possibile bloccare l'hash utilizzando una delle funzioni da Hash::Util (un modulo di base).

use Hash::Util qw(lock_keys unlock_keys); 

my $some_ref = { akey => { deeper => 1 } }; 
lock_keys %$some_ref; 

print "too deep" if $some_ref->{deep}{shit} == 1; 

Ora l'ultima dichiarazione sarà un'eccezione:

Attempt to access disallowed key 'deep' in a restricted hash 

Il rovescio della medaglia è, naturalmente, che dovrete stare molto attenti quando si controlla per le chiavi nella hash per evitare eccezioni, vale a dire utilizzare una lof di "if exists ..." per verificare la presenza di chiavi prima di accedervi.

Se è necessario aggiungere le chiavi per l'hash in un secondo momento è possibile sbloccarlo:

unlock_keys %$some_ref; 
$some_ref->{foo} = 'bar'; # no exception 
+0

Beh sì, ma questa è una grande app. e immagina che l'hash sia una sessione legata. Grazie. –

3

I upvoted @zoul, ma si dovrebbe prendere un ulteriore passo avanti.

Test Write

si dovrebbe avere il codice di coperte di test, e si dovrebbe eseguire alcuni di questi test con

use warnings FATAL => 'uninitialized'; 

dichiarato nel test-caso in sé. È l'unico modo per affrontare la preoccupazione che hai con gli sviluppatori che non controllano le cose in anticipo correttamente. Assicurati che il loro codice sia testato.

E fai un altro passo avanti e semplifica l'esecuzione dei test sotto Devel::Cover per ottenere un rapporto sulla copertura.

cover -delete 
PERL5OPT='-MDevel::Cover' prove -l 
cover -report Html_basic 

e quindi controllare le righe di codice e le dichiarazioni vengono eseguite dai test, altrimenti rendendo tali avvertimenti fatale sarà solo fare morire il codice in un momento inaspettato dopo.

+1

Non hai bisogno di FATAL => 'non inizializzato' per questo. Il modulo Test :: Avvisa ti consentirà di verificare che hai ricevuto gli avvisi corretti (o l'assenza di avvisi) dai tuoi casi di test. –

+0

"Scrivi test" è abbastanza facile da dire :). Ho iniziato a farlo, ma come sai i compiti sono in attesa Nel frattempo ho bisogno di qualcosa di più facile da fare. Grazie per il voto. Sto considerando di andare con FATAL => 'non inizializzato' nell'ambiente di sviluppo. –

+0

gli avvertimenti di utilizzo sono in ambito lessicale, quindi averlo nel test non lo abilita nel codice in fase di test. – ysth

1

Un'altra opzione è utilizzare Data::Diver per accedere alle strutture dati.

if(1 == Dive($some_ref, qw/ deep structures are not autovivified now /) { 
    Do_Stuff(); 
} 
+0

Grazie, volevo solo un modo rapido per risolvere il mio problema e interrompere ulteriori comportamenti scorretti. Aggiungerò alla mia domanda un modello semplificato della soluzione. –

21

Relativamente nuovo è il modulo autovivification, che ti permette di fare questo:

no autovivification; 

piuttosto semplice.

+0

Lo proverò. Funziona bene con hash/array legati? –

+2

il link corrente non dipendente dalla versione: http://search.cpan.org/~vpit/autovivification/ –

+0

Grazie ... ha aggiornato il collegamento nella risposta. – oeuftete