2009-04-26 13 views
7

Supongamos que tiene una GRAN aplicación "desarrollada";) por un gran equipo. Aquí hay un modelo simplificado del desastre potencial que puede ocurrir cuando alguien comprueba demasiado profundamente en una estructura de datos. Si no es posible desactivar completamente la autovificación o en el alcance, ¿cómo evitar esto? Muchas gracias :) !!!!¿Cómo desactivo la autovibición en 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); 

Esto da el siguiente resultado:

$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í sé que no es una advertencia, pero ... puede que sea demasiado tarde.

Hola chicos, puede ser útil decir que mi hashref hace referencia a un HASH vinculado.

¿Puede ser que si implemento un buen método FETCH que compruebe los controles más profundos en la estructura, resolveré fácilmente mi problema?


Miré a Tie::StrictHash, y Tie::Hashperltie. versión simplificada de Aquí está mi solución:

#!/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 '.$/; 
} 

lo que he conseguido es tocar un solo lugar en la aplicación. Ahora todos los lugares como if ($ some_ref -> {deep} {doot}) causarán la muerte con stack-trace. Así que los encontraré y corregiré fácilmente. Y nuevas escrituras de este tipo NO serán posibles. Perl también es bueno para grandes aplicaciones, solo necesita saber más;).

¡Gracias a todos! Espero que esto ayude a otros también.

+0

¿Cuál es su pregunta? –

+0

¿Cómo desactivo la autovibición en Perl? –

Respuesta

15

Es posible que desee utilizar un objeto en lugar del hash (consulte Moose) o utilice un strict tied hash. O puede activar avisos en errores, si realmente quiere:

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

+1, FATAL en sin inicializar para la victoria. –

+0

Puede ser, como dice Kent, usar advertencias NONFATAL => 'all', FATAL => 'uninitized'; es la forma más aceptable de hacerlo. Es posible que tenga esta configuración en desarrollo. Dejaré la pregunta un poco más, solo para ver si alguien sugiere algo aún más inteligente :). Gracias. –

+0

Me acabo de dar cuenta de que necesito escribir algo de verificación en mi método FETCH ya que mis puntos de referencia a Tied HASH en realidad. Muchas gracias realmente. –

9

Puede bloquear el hash utilizando una de las funciones de Hash::Util (un módulo básico).

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; 

Ahora la última declaración será una excepción:

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

La desventaja es, por supuesto, que tendrá que ser muy cuidadoso en la comprobación de las claves en el hash para evitar excepciones, es decir, use un lof de "if exists ..." para verificar las claves antes de acceder a ellas.

Si es necesario agregar claves para el hash de nuevo más tarde puede desbloquearlo:

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

Bueno, sí, pero esta es una gran aplicación. e imagina que el hash es una Sesión atado. Gracias. –

3

I upvoted @zoul, pero se debe dar un paso más allá.

pruebas de escritura

usted debe tener su código de cubiertas de pruebas, y se debe ejecutar algunas de esas pruebas con

use warnings FATAL => 'uninitialized'; 

declarado en el mismo caso de prueba. Es la única forma de abordar la preocupación que tienes con los desarrolladores que no verifican las cosas con anticipación. Asegúrate de que su código esté probado.

Y dar un paso más allá, y hacer que sea más fácil ejecutar sus pruebas bajo Devel::Cover para obtener un informe de cobertura.

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

y después comprobar las líneas de código y las declaraciones están siendo ejecutados por las pruebas, de lo contrario hacer esas advertencias fatales se acaba de hacer código mueren en un momento inesperado después.

+1

No necesita FATAL => 'no inicializado' para esto. El módulo Test :: Warn le permitirá probar que recibió las advertencias correctas (o la ausencia de advertencias) de sus casos de prueba. –

+0

"Escribir pruebas" es bastante fácil de decir :). Empecé a hacerlo, pero como saben, las tareas están esperando Mientras tanto, necesito algo más fácil de hacer. Gracias por la votación. Estoy considerando ir con FATAL => 'no inicializado' en el entorno de desarrollo. –

+0

use warnings tiene un alcance léxico, por lo que tenerlo activado en la prueba no lo habilita en el código que se está probando. – ysth

1

Otra opción es utilizar Data::Diver para acceder a sus estructuras de datos.

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

Gracias, solo quería una manera rápida de resolver mi problema y descontinuar cualquier otro mal comportamiento. Agregaré a mi pregunta un modelo simplificado de la solución. –

21

relativamente nuevo es el módulo autovivification, lo que le permite hacer esto:

no autovivification; 

bastante sencillo.

+0

Lo intentaré. ¿Funciona bien con hashes/arrays atados? –

+2

el enlace actual no dependiente de la versión: http://search.cpan.org/~vpit/autovivification/ –

+0

Gracias ... actualizó el enlace en la respuesta. – oeuftete

Cuestiones relacionadas