2009-04-26 2 views
7

Предположим, что у вас есть ОГРОМНОЕ приложение «Разработано»;) большой командой. Вот упрощенная модель потенциального бедствия, которое может произойти, когда кто-то слишком глубоко проверяет структуру данных. Если невозможно полностью отключить автовизацию или в области действия, как обойти это? Большое спасибо :) !!!!Как отключить автовивитацию в 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); 

Это выводит следующее:

$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 
        } 
     }; 

Да, я знаю, что это предупреждение, но ... это может быть слишком поздно.

Эй, ребята, может быть, это поможет сказать, что мой hashref ссылается на связанный HASH.

Может быть, если я реализую хороший метод FETCH, который проверяет глубину проверки в структуре, я легко решаю мою проблему?


Я смотрел на Tie::StrictHash, Tie::Hash и perltie. Вот упрощенная версия моего решения:

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

То, что я достиг, чтобы коснуться только одно место в приложении. Теперь все Места как if ($ some_ref -> {deep} {doot}) вызовут смерть со стеком-трассировкой. Так что я легко их найду и исправлю. И новые писания такого рода НЕ будут возможны. Perl хорош для больших приложений тоже, вам просто нужно знать больше;).

Спасибо всем! Я надеюсь, что это тоже поможет другим.

+0

Что вы думаете об этом? –

+0

Как отключить автовивитацию в perl? –

ответ

15

Возможно, вы захотите использовать объект вместо хэша (см. Moose) или используйте strict tied hash. Или вы можете включить предупреждения в ошибки, если вы действительно хотите:

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

+1, FATAL на неинициализированном для победы. –

+0

Может быть, как говорит Кент, использовать предупреждения NONFATAL => 'all', FATAL => 'uninitialized'; является наиболее приемлемым способом. Возможно, у меня это настроено в разработке. Я оставлю вопрос еще немного, просто чтобы узнать, подскажет ли кто-нибудь что-нибудь даже умнее :). Спасибо. –

+0

Я только что понял, что мне нужно написать только чек в моем методе FETCH, так как на самом деле мои ссылки на Tied HASH. Спасибо, очень много. –

9

Вы можете заблокировать хэш с помощью одной из функций из Hash::Util (основной модуль).

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; 

Теперь последнее утверждение будет сгенерировано исключение:

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

Недостатком является то, конечно, что вы должны быть очень осторожны при проверке ключей в хэш, чтобы избежать исключения, т. е. использовать ключ «if exists ...» для проверки ключей перед их доступом.

Если вам нужно добавить ключи к хэш позже вы можете разблокировать:

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

Ну да, но это большое приложение. и представьте, что хэш - это связанная сессия. Спасибо. –

3

Я upvoted @zoul, но вы должны принять это один шаг дальше.

Запись Тесты

Вы должны иметь свой код, охватываемые с тестами, и вы должны запустить некоторые из этих тестов с

use warnings FATAL => 'uninitialized'; 

объявлен в самом тестовом случае. Это единственный способ решить проблему, с которой вы сталкиваетесь с разработчиками, не проверяя заранее. Убедитесь, что их код проверен.

И сделайте еще один шаг вперед, и попробуйте провести тесты под номером Devel::Cover, чтобы получить отчет о покрытии.

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

А затем проверьте строки кода и утверждения выполняется с помощью тестов, в противном случае делает эти предупреждения со смертельным исходом будет просто сделать код умереть в неожиданное время спустя.

+1

Для этого вам не нужен FATAL => 'uninitialized'. Модуль Test :: Warn позволит вам проверить, что вы получили правильные предупреждения (или отсутствие предупреждений) из ваших тестовых случаев. –

+0

«Write Tests» довольно легко сказать :). Я начал это делать, но, как вы знаете, задачи ждут Между тем мне нужно что-то более легкое сделать. Спасибо, что голосовали. Я рассматриваю возможность использования FATAL => 'uninitialized' в среде разработки. –

+0

Предупреждения об использовании лексически ограничены, поэтому включение этого теста не позволяет включить его в тестируемый код. – ysth

1

Другим вариантом является использование Data::Diver для доступа к вашим структурам данных.

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

Спасибо, я просто хотел быстро решить мою проблему и прекратить дальнейшее проступки. Я добавлю к моему вопросу упрощенную модель решения. –

21

Относительно новым является модуль autovivification, который позволяет это сделать:

no autovivification; 

Довольно просто.

+0

Я попробую. Он работает нормально с привязанными хешами/массивами? –

+2

текущая ссылка, не зависящая от версии: http://search.cpan.org/~vpit/autovivification/ –

+0

Спасибо ... обновил ссылку в ответе. – oeuftete

Смежные вопросы