2010-01-19 15 views
9

कुछ समय पहले, मैंने This question से बिल्डिंग पर्ल कार्यों को ओवरराइड करने के बारे में पूछा।मैं एकाधिक ओवरराइड सक्षम करने, पर्ल फ़ंक्शंस को ओवरराइड कैसे कर सकता हूं?

मैं ऐसा कैसे कर सकता हूं जो एकाधिक ओवरराइड की अनुमति देता है? निम्नलिखित कोड एक अनंत रिकर्सन पैदा करता है।

ऐसा करने का सही तरीका क्या है? यदि मैं किसी फ़ंक्शन को फिर से परिभाषित करता हूं, तो मैं किसी और के पुनर्वितरण पर कदम नहीं उठाना चाहता हूं।

package first; 

my $orig_system1; 
sub mysystem { 
    my @args = @_; 
    print("in first mysystem\n"); 
    return &{$orig_system1}(@args); 
} 

BEGIN { 

    if (defined(my $orig = \&CORE::GLOBAL::system)) { 
    $orig_system1 = $orig; 
    *CORE::GLOBAL::system = \&first::mysystem; 
    printf("first defined\n"); 
    } else { 
    printf("no orig for first\n"); 
    } 
} 

package main; 

system("echo hello world"); 

उत्तर

20

ऐसा करने का उचित तरीका यह नहीं है। आप जो कर रहे हैं उसे पूरा करने के लिए कुछ और तरीका ढूंढें। इस तकनीक में वैश्विक चर, वर्ग की सभी समस्याएं हैं। जब तक आप फ़ंक्शन के ठीक से पुनः लिख नहीं लेते, तब तक आप उस कोड के सभी प्रकार को तोड़ सकते हैं जिसे आप कभी भी नहीं जानते थे। और जब आप एक मौजूदा ओवरराइड पर उड़ने में विनम्र हो सकते हैं, तो शायद कोई और नहीं होगा।

ओवरराइडिंग system विशेष रूप से स्पर्शपूर्ण है क्योंकि इसमें उचित प्रोटोटाइप नहीं है। ऐसा इसलिए है क्योंकि यह प्रोटोटाइप सिस्टम में चीजों को व्यक्त नहीं करता है। इसका मतलब है कि आपका ओवरराइड कुछ चीजें नहीं कर सकता है जो system कर सकते हैं। अर्थात् ...

system {$program} @args; 

यह एक वैध तरीका system कॉल करने के लिए, हालांकि आप यह करने के लिए exec डॉक्स पढ़ने की जरूरत है। आप सोच सकते हैं "ओह, ठीक है, मैं बस ऐसा नहीं करूँगा", लेकिन यदि आप जिस मॉड्यूल का उपयोग करते हैं, वह करता है, या इसका उपयोग करने वाला कोई भी मॉड्यूल करता है, तो आप भाग्य से बाहर हैं।

उस ने कहा, विनम्रतापूर्वक किसी भी अन्य कार्य को ओवरराइड करने से थोड़ा अलग है। आपको मौजूदा फ़ंक्शन को फंसाना होगा और सुनिश्चित करें कि आप इसे अपने नए में कॉल करें। चाहे आप इससे पहले या बाद में करते हैं।

आपके कोड में समस्या यह है कि फ़ंक्शन परिभाषित किया गया है या नहीं, यह जांचने का उचित तरीका defined &function है। एक अपरिभाषित फ़ंक्शन का भी एक कोड रेफरी लेना, हमेशा एक सच्चा कोड रेफरी वापस कर देगा। मुझे यकीन नहीं है कि क्यों, शायद \undef एक स्केलर रेफरी वापस करेगा। इस कोड रेफ को क्यों कॉल करना mysystem() को असीमित रूप से रिकर्सिव करने के लिए किसी का अनुमान है।

इसमें एक अतिरिक्त जटिलता है कि आप कोर फ़ंक्शन का संदर्भ नहीं ले सकते हैं। \&CORE::system आपका मतलब नहीं है। न ही आप इसे प्रतीकात्मक संदर्भ के साथ प्राप्त कर सकते हैं। इसलिए यदि आप CORE::system या मौजूदा ओवरराइड को कॉल करना चाहते हैं, जिस पर परिभाषित किया गया है, तो आप केवल एक या दूसरे को कोड रेफरी पर असाइन नहीं कर सकते हैं। आपको अपने तर्क को विभाजित करना होगा।

यहां ऐसा करने का एक तरीका है।

package first; 

use strict; 
use warnings; 

sub override_system { 
    my $after = shift; 

    my $code; 
    if(defined &CORE::GLOBAL::system) { 
     my $original = \&CORE::GLOBAL::system; 

     $code = sub { 
      my $exit = $original->(@_); 
      return $after->($exit, @_); 
     }; 
    } 
    else { 
     $code = sub { 
      my $exit = CORE::system(@_); 
      return $after->($exit, @_); 
     }; 
    } 

    no warnings 'redefine'; 
    *CORE::GLOBAL::system = $code; 
} 

sub mysystem { 
    my($exit, @args) = @_; 
    print("in first mysystem, got $exit and @args\n"); 
} 

BEGIN { override_system(\&mysystem) } 

package main; 

system("echo hello world"); 

ध्यान दें कि मैं mysystem() बदल दिया है केवल एक हुक है कि वास्तविक प्रणाली के बाद चलता है किया जाना है। यह सभी तर्क और निकास कोड प्राप्त करता है, और यह निकास कोड बदल सकता है, लेकिन यह system() वास्तव में नहीं बदलता है। हुक के पहले/बाद में जोड़ना एकमात्र चीज है जो आप कर सकते हैं यदि आप मौजूदा ओवरराइड का सम्मान करना चाहते हैं। वैसे भी यह थोड़ा सा सुरक्षित है। ओवरराइडिंग सिस्टम की गड़बड़ी अब एक अव्यवस्था में है जो BEGIN को बहुत अव्यवस्थित होने से रोकती है।

आपको अपनी आवश्यकताओं के लिए इसे संशोधित करने में सक्षम होना चाहिए।

संबंधित मुद्दे

 संबंधित मुद्दे