2011-09-29 9 views
15

पर्ल के eval से जुड़े सामान्य नुकसान क्या हैं, जो आपको Try::Tiny जैसे मॉड्यूल का उपयोग करने का विकल्प चुन सकते हैं?पर्ल के eval का उपयोग करते समय आम नुकसान क्या हैं?

+0

की [क्यों '$ है संभव डुप्लिकेट @ 'अविश्वसनीय?] (http://stackoverflow.com/questions/3686857/why-is-untrustworthy), [पर्ल में अपवादों के बारे में क्या टूटा हुआ है?] (http://stackoverflow.com/questions/2165161/) – mob

+2

केवल फिर से जैसा कि आप बिल्टिन का उपयोग नहीं करेंगे, आप पर्ल का वर्तमान संस्करण नहीं चला रहे हैं। – tchrist

+0

@mob - हाँ, यह वही प्रश्न प्रतीत होता है। – Hugh

उत्तर

25

पर्ल के eval दो जायके, स्ट्रिंग eval और ब्लॉक eval में आता है। स्ट्रिंग eval स्रोत कोड निष्पादित करने के लिए संकलक को आमंत्रित करता है। ब्लॉक eval पहले से संकलित कोड एक रैपर में घिरा हुआ है जो die अपवाद पकड़ जाएगा। (स्ट्रिंग eval die अपवाद भी, साथ ही किसी भी संकलन त्रुटियों को पकड़ता है)।

कोशिश करें :: छोटे केवल eval के ब्लॉक रूप पर लागू होता है, लेकिन निम्नलिखित दोनों रूपों पर लागू होता है।

हर बार जब आप eval पर कॉल करते हैं तो यह [email protected] का मान बदल देगा। अगर eval सफल हुआ या eval द्वारा पकड़ा त्रुटि अगर यह '' होगा।

इसका मतलब है कि जब भी आप एक eval कहते हैं, तो आप किसी भी पिछले त्रुटि संदेश को साफ़ कर देंगे। Try::Tiny आपके लिए [email protected] वैरिएबल को स्थानांतरित करता है, ताकि एक सफल eval पिछले विफल eval के संदेश को साफ़ नहीं करेगा।

अन्य pitfall [email protected] का उपयोग करके यह जांचने के लिए आता है कि eval सफल हुआ है या नहीं। एक आम पैटर्न है:

eval {...}; 
if ([email protected]) { 
    # deal with error here 
} 

यह दो मान्यताओं पर निर्भर करता है, पहला यह है कि किसी भी त्रुटि संदेश [email protected] हो सकता है एक सही मूल्य (आमतौर पर सही) है, और वहाँ eval ब्लॉक और अगर बयान के बीच कोई कोड नहीं है।

दिखने के पाठ्यक्रम बाद सही है, लेकिन eval ब्लॉक एक वस्तु बनाया है, और बाद eval, विफल रहा है तो वस्तु की DESTROY विधि if बयान से पहले बुलाया जाएगा कि वस्तु क्षेत्र से बाहर चला गया है। यदि DESTROY[email protected] को स्थानीयकृत किए बिना eval कॉल होता है और यह सफल होता है, तब तक जब आपका if कथन चलाया जाता है, तो [email protected] चर साफ़ हो जाएगा।

समाधान इन समस्याओं के लिए है:

my $return = do { 
    local [email protected]; 
    my $ret; 
    eval {$ret = this_could_fail(); 1} or die "eval failed: [email protected]"; 
    $ret 
}; 

लाइन द्वारा कि अलग लाइन तोड़ने, local [email protected]do ब्लॉक जो पिछले मान clobbering रोकता है के लिए एक नया [email protected] पैदा करता है। my $ret मूल्यांकन कोड का वापसी मूल्य होगा। Eval ब्लॉक में, $ret को असाइन किया गया है, और फिर ब्लॉक 1 देता है। इस तरह, कोई फर्क नहीं पड़ता कि, अगर eval सफल होता है यह सच हो जाएगा, और अगर यह विफल रहता है तो यह झूठी वापसी होगी। असफलता के मामले में क्या करना है यह आपके ऊपर है। ऊपर दिया गया कोड बस मर जाता है, लेकिन आप अन्य कोड चलाने का निर्णय लेने के लिए आसानी से eval ब्लॉक के वापसी मूल्य का उपयोग कर सकते हैं।

चूंकि उपरोक्त incantation थोड़ा कठिन है, यह त्रुटि प्रवण हो जाता है।Try::Tiny जैसे मॉड्यूल का उपयोग करके आप उन संभावित त्रुटियों से इन्सुलेट करते हैं, प्रति eval कुछ और फ़ंक्शन कॉल की लागत पर। यह जानना महत्वपूर्ण है कि कैसे eval ठीक से उपयोग करें, क्योंकि Try::Tiny आपको स्ट्रिंग eval का उपयोग करने के लिए मदद नहीं करेगा।

+4

वर्तमान रिलीज में फिक्स्ड। – tchrist

+0

छोटे सुधार - अगर कोई अपवाद नहीं फेंक दिया गया तो '$ @ 'वास्तव में अनावश्यक के बजाय एक खाली स्ट्रिंग होगी। –

+1

@ ग्रैंट मैकलीन => धन्यवाद, मुझे याद रखना चाहिए था, क्योंकि इस तरह मेरी सामान्य प्रतिलिपि त्रुटियों से संबंधित है: 'perl -wE' eval, $ @ जबकि <> ' –

11

मुद्दों को Try::Tiny documentation में समझाया गया है। संक्षेप में, वे हैं:

+0

धन्यवाद। हालांकि मैंने कोशिश करें: टिनी पर परिचय पढ़ा, मैं पृष्ठभूमि अनुभाग को पढ़ने में विफल रहा। – Hugh

+2

वर्तमान रिलीज में फिक्स्ड। – tchrist

6

ऊपर जवाब के अलावा, मैं जोड़ना होगा ...

  • eval दूरी पर वैश्विक $SIG{__DIE__} हैंडलर के कारण कार्रवाई से प्रभावित है।
  • नौसिखिए को eval BLOCK और eval STRING को भ्रमित करना आसान है, क्योंकि वे एक ही काम करते हैं, लेकिन एक सुरक्षा छेद है।

कोशिश करें :: छोटे के अपने नुकसान हैं, सबसे बड़ा यह है कि यह एक ब्लॉक की तरह दिखता है, यह वास्तव में एक सबराउटिन कॉल है। इसका मतलब है कि यह:

eval { 
    ...blah blah... 
    return $foo; 
}; 

और इस:

try { 
    ...blah blah... 
    return $foo; 
}; 

एक ही बात नहीं करते हैं। ये CAVEATS section of the Try::Tiny docs में रखे गए हैं। उस ने कहा, मैं इसे eval से अधिक अनुशंसा करता हूं।

+2

कह रहे हैं कि' eval' है * अभी भी * 5.14 में असामान्य रूप से टूटा हुआ? ** वास्तव में? ** यह * बेहद निराशाजनक होगा, क्योंकि मुझे पता है कि 'eval' को प्रभावित करने वाली अंतर्निहित बग को ठीक करके 'ट्री :: टिनी' अप्रचलित प्रस्तुत करने का प्रयास करने के लिए बहुत सारे काम किए गए हैं।यदि वह प्रयास विफल हुआ, तो एक भयानक समस्या है क्योंकि 'Try :: Tiny' अभी भी केवल एक CPAN मॉड्यूल है, कोर नहीं। यदि आप मूल कार्य नहीं कर सकते हैं, और विश्वसनीय रूप से, कोर के साथ, तो यह एक अस्वीकार्य स्थिति है। – tchrist

+1

@tchrist इसके बारे में भूल गए। जैसा कि मैंने इसे समझ लिया है, 5.14.0 ने $ @ और ऑब्जेक्ट विनाश के बीच बातचीत के साथ होने वाली बगों की एक श्रेणी तय की है और आम तौर पर 'eval {...} बनाया है; अगर ($ @) {...} 'अधिक विश्वसनीय। मेरा मानना ​​है कि 3 चीजों में से 2 हल करने का प्रयास करें :: छोटे फिक्स ... और तीसरा (एक झूठा $ @) बहुत असंभव है। यह अभी भी मैंने बताए गए अंक छोड़ देता है। एक eval के अंदर फायरिंग से '$ SIG {__ DIE __} 'को रोकने के लिए यह एक अच्छा 5.16 सुविधा होगी। और नाटक, दोस्त को डायल करें। – Schwern

+0

'eval STRING' को कॉल करना "सुरक्षा समस्या" केवल अत्यधिक नाटकीय नहीं है; यह भी सच नहीं है। मैंने 'eval STRING' का उपयोग किया है क्योंकि यह पहली बार बीस-तीन साल पहले perl2 में दिखाई दिया था, मैं आपको आश्वस्त कर सकता हूं कि कभी कभी मुझे इसके साथ किसी भी तथाकथित" सुरक्षा समस्या "का अनुभव नहीं हुआ है। निश्चित रूप से, गूंगा प्रोग्रामर इसके साथ गूंगा चीजें कर सकते हैं, लेकिन यह लगभग किसी भी चीज़ के बारे में सच है। यदि आप पैथोलॉजिकल पागल दुनिया में मौजूद हैं, तो आपको टेंट मोड और/या सुरक्षित डिब्बों का उपयोग करना चाहिए। एक सामान्य दुनिया में, 'eval STRING' को बहुत उपयोगी काम मिल जाता है; क्लासिक * नाम बदलें * कार्यक्रम देखें। – tchrist

0

एक्स 11 फ़ंक्शन पर eval का उपयोग करना अभी भी जिंदा रखने में विफल रहा है।

तरह

eval {  
    @win_arrays = GetWindowsFromPid($pid); 
}; 

स्क्रिप्ट से विफल अनुरोध के

एक्स त्रुटि से बाहर निकल गया हो जाएगा कोड है: ...