2009-04-26 38 views
7

Giả sử bạn có một ứng dụng HUGE "develoopped";) bởi một nhóm lớn. Đây là một mô hình đơn giản của thảm họa tiềm năng có thể xảy ra khi ai đó kiểm tra quá sâu trong cấu trúc dữ liệu. Nếu không thể tắt hoàn toàn tự động hoặc trong phạm vi, cách khắc phục sự cố này? Cảm ơn bạn rất nhiều :) !!!!Làm cách nào để tắt tính năng tự động hóa trong 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); 

này kết quả đầu ra như sau:

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

Có, tôi biết có một cảnh báo, nhưng ... nó có thể là quá muộn.

Xin chào các bạn, tôi có thể nói rằng hashref của tôi tham chiếu đến HASH bị ràng buộc.

Có thể nếu tôi triển khai phương pháp FETCH tốt để kiểm tra xem có sâu hơn trong cấu trúc không, tôi sẽ giải quyết dễ dàng vấn đề của tôi?


Tôi nhìn Tie::StrictHash, Tie::Hashperltie. Đây là phiên bản đơn giản của giải pháp của tôi:

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

Điều tôi đạt được chỉ là chạm vào một vị trí trong ứng dụng. Bây giờ tất cả các Địa điểm như nếu ($ some_ref -> {deep} {doot}) sẽ gây chết với stack-trace. Vì vậy, tôi sẽ dễ dàng tìm thấy chúng và sửa chúng. Và các tác phẩm mới của loại này sẽ KHÔNG thể thực hiện được. Perl cũng tốt cho các ứng dụng lớn, bạn chỉ cần biết nhiều hơn;).

Cảm ơn tất cả! Tôi hy vọng điều này cũng giúp người khác.

+0

câu hỏi của bạn là gì? –

+0

Làm cách nào để tắt tính năng tự động hóa trong perl? –

Trả lời

15

Bạn có thể muốn sử dụng đối tượng thay vì băm (xem Moose) hoặc sử dụng strict tied hash. Hoặc bạn có thể tắt cảnh báo vào lỗi, nếu bạn thực sự muốn:

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

+1, FATAL trên uninitialized cho chiến thắng. –

+0

Có thể, như Kent nói, sử dụng cảnh báo NONFATAL => 'all', FATAL => 'uninitialized'; là cách có thể chấp nhận được nhất. Tôi có thể thiết lập tính năng này trong quá trình phát triển. Tôi sẽ để lại câu hỏi nhiều hơn một chút, chỉ để xem liệu có ai đó sẽ gợi ý điều gì đó thậm chí thông minh hơn không :). Cảm ơn bạn. –

+0

Tôi chỉ nhận ra rằng tôi cần phải viết một số kiểm tra trong phương pháp FETCH của tôi từ điểm tham chiếu của tôi đến một HASH Tied thực sự. Cảm ơn rất nhiều. –

9

Bạn có thể khóa băm bằng một trong những chức năng từ Hash::Util (một module lõi).

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; 

Bây giờ báo cáo kết quả cuối cùng sẽ ném một ngoại lệ:

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

Nhược điểm là, tất nhiên, bạn sẽ phải rất cẩn thận khi kiểm tra các phím trong băm để tránh trường hợp ngoại lệ, tức là sử dụng một lof của "if exists ..." để kiểm tra các khóa trước khi bạn truy cập chúng.

Nếu bạn cần thêm chìa khóa để băm lại sau bạn có thể mở khóa nó:

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

Vâng, nhưng đây là một ứng dụng lớn. và tưởng tượng băm là một phiên liên kết. Cảm ơn bạn. –

3

Tôi upvoted @zoul, nhưng bạn nên mang nó một bước xa hơn.

viết bài kiểm tra

Bạn nên mã của bạn được bảo hiểm với các bài kiểm tra, và bạn nên chạy một số những thử nghiệm với

use warnings FATAL => 'uninitialized'; 

tuyên bố trong các thử nghiệm trường riêng của mình. Cách duy nhất để giải quyết mối quan tâm của bạn với các nhà phát triển không kiểm tra mọi thứ trước một cách chính xác. Đảm bảo mã của họ được kiểm tra.

Và tiến thêm một bước nữa, và giúp bạn dễ dàng chạy thử nghiệm theo Devel::Cover để nhận báo cáo bảo hiểm.

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

Và sau đó kiểm tra các dòng mã và câu lệnh đang được thực hiện bởi các kiểm tra, nếu không thì những cảnh báo đó sẽ chỉ khiến mã chết vào một thời điểm bất ngờ sau đó.

+1

Bạn không cần FATAL => 'uninitialized' cho việc này. Kiểm tra :: Mô-đun cảnh báo sẽ cho phép bạn kiểm tra rằng bạn đã nhận được cảnh báo chính xác (hoặc không có cảnh báo) từ các trường hợp thử nghiệm của bạn. –

+0

"Viết thử nghiệm" là khá dễ dàng để nói :). Tôi bắt đầu làm điều đó, nhưng như bạn biết các nhiệm vụ đang chờ đợi Trong khi đó tôi cần một cái gì đó dễ dàng hơn để làm. Cảm ơn bạn đã bỏ phiếu. Tôi đang xem xét đi với FATAL => 'uninitialized' trong môi trường phát triển. –

+0

sử dụng các cảnh báo bị lốm đốm một cách lố bịch, vì vậy việc cảnh báo trong thử nghiệm không cho phép nó trong mã đang được thử nghiệm. – ysth

1

Một tùy chọn khác là sử dụng Data::Diver để truy cập vào cấu trúc dữ liệu của bạn.

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

Cảm ơn, tôi chỉ muốn có một cách nhanh chóng để giải quyết vấn đề của mình và ngừng tiếp tục hành vi sai trái. Tôi sẽ thêm vào câu hỏi của tôi một mô hình đơn giản của giải pháp. –

21

tương đối mới là module autovivification, cho phép bạn làm điều này:

no autovivification; 

Khá đơn giản.

+0

Tôi sẽ thử. Liệu nó hoạt động ok với băm gắn kết/mảng? –

+2

liên kết phụ thuộc phiên bản không hiện tại: http://search.cpan.org/~vpit/autovivification/ –

+0

Cảm ơn ... đã cập nhật liên kết trong phản hồi. – oeuftete

Các vấn đề liên quan