2009-07-31 15 views
20

में कोई विधि कहा जाता है, क्या PHP में कोई तरीका है कि यह पता लगाने के लिए कि किसी अन्य ऑब्जेक्ट में कौन सी विधि कहलाती है।पता लगाएं कि किस वर्ग को किसी अन्य वर्ग

उदाहरण के:

class Foo 
{ 
    public function __construct() 
    { 
    $bar = new Bar(); 
    $bar->test(); 
    } 
} 

class Bar 
{ 
    public function test() 
    { 
    } 
} 
$foo = new Foo(); 

मुझे पता लगाने के लिए के लिए है कि परीक्षण विधि foo वस्तु से बुलाया गया था एक तरह से वहाँ होगा?

उत्तर

46

आप debug_backtrace, इस्तेमाल कर सकते हैं इस तरह एक सा:
Btw, मैनुअल पृष्ठ पर मौजूद टिप्पणियों पर एक नज़र डालें: कुछ उपयोगी कार्य करता है और सलाह दी देखते हैं ;-)

class Foo 
{ 
    public function __construct() 
    { 
    $bar = new Bar(); 
    $bar->test(); 
    } 
} 

class Bar 
{ 
    public function test() 
    { 
     $trace = debug_backtrace(); 
     if (isset($trace[1])) { 
      // $trace[0] is ourself 
      // $trace[1] is our caller 
      // and so on... 
      var_dump($trace[1]); 

      echo "called by {$trace[1]['class']} :: {$trace[1]['function']}"; 

     } 
    } 
} 
$foo = new Foo(); 

var_dump होगा उत्पादन:

array 
    'file' => string '/home/squale/developpement/tests/temp/temp.php' (length=46) 
    'line' => int 29 
    'function' => string '__construct' (length=11) 
    'class' => string 'Foo' (length=3) 
    'object' => 
    object(Foo)[1] 
    'type' => string '->' (length=2) 
    'args' => 
    array 
     empty 

और echo:

called by Foo :: __construct 

लेकिन, जैसा कि यह अच्छा लग सकता है, मुझे यकीन नहीं है कि यह आपके आवेदन में "सामान्य चीज़" के रूप में उपयोग किया जाना चाहिए ... अजीब लगता है, वास्तव में: एक अच्छी डिजाइन के साथ, एक विधि की आवश्यकता नहीं होनी चाहिए यह जानने के लिए कि इसे क्या कहा जाता है, मेरी राय में।

+2

कार्य उदाहरण हमेशा अच्छे होते हैं। +1। :) – Randolpho

+0

धन्यवाद ;-) (वे पहले जवाब प्राप्त करने का भी कारण नहीं हैं ^^ लेकिन, कम से कम, मेरे पास थोड़ा मजा भी है, इस तरह ;-)) –

+1

उदाहरण के लिए धन्यवाद। हां, मैं कुछ हद तक सहमत हूं, कि विधियों को जानने की आवश्यकता नहीं है, लेकिन मेरे पास कुछ अन्य लोग जो लिख रहे हैं उसके शीर्ष पर कोड लिख रहे हैं और मैं उनका जीवन आसान बनाना चाहता हूं, वह। मुझे लगता है कि डीबग का उपयोग करना थोड़ा हैकिश है, लेकिन धन्यवाद, आपने मुझे डिबगिंग फ़ंक्शन में एक अच्छी अंतर्दृष्टि दी है, कुछ आईडी पहले कभी नहीं हुई थी। – Botto

2

आप इसे debug backtrace के साथ प्राप्त कर सकते हैं, हालांकि यह एक प्रकार का हैकिश लगता है।

आपका वैकल्पिक विकल्प उस वर्ग के पैरामीटर को पास करना है और उसे बताएं कि इसे कहां से बुलाया जा रहा है, जब आप कक्षा को दूसरे के भीतर से तुरंत चालू करते हैं।

+0

मैंने पहले इस देखा है और यह समय है कि एक पश्व-अनुरेखन ही एकमात्र विकल्प था पर लग रहा था। – UnkwnTech

2

कम से कम, आप debug_backtrace का उपयोग कर सकते हैं और कॉलिंग विधि ढूंढने के लिए इसका विश्लेषण कर सकते हैं।

मुझे लगता है कि आपको reflection API का उपयोग करके भी ऐसा करने में सक्षम होना चाहिए, लेकिन यह बहुत लंबा रहा है क्योंकि मैंने PHP का उपयोग किया है और मुझे बिल्कुल याद नहीं है। लिंक्स कम से कम आपको शुरू करना चाहिए, हालांकि।

2

@ पास्कल मार्टिन: हां, सामान्य आवेदकों में इसकी शायद आवश्यकता नहीं है। लेकिन कभी-कभी यह उपयोगी हो सकता है। अपने ऐप से एक उदाहरण पर विचार करें:

एक नियंत्रक सबक्लास है जो अपने आउटपुट को तैयार करने के लिए टेम्पलेट ऑब्जेक्ट का उपयोग कर सकता है। प्रत्येक टेम्पलेट का नाम इसका नाम है। जब एक नियंत्रक को टेम्पलेट की आवश्यकता होती है, तो वह उस नाम को पैरामीटर के रूप में देकर टेम्पलेट प्रबंधक से पूछता है। लेकिन अलग-अलग नियंत्रकों के लिए उस नाम के साथ कई टेम्पलेट फ़ाइलें हो सकती हैं। नियंत्रक प्लगइन के रूप में उपयोग किए जाते हैं, और विभिन्न उपयोगकर्ताओं द्वारा लिखे जा सकते हैं, इसलिए उनके द्वारा उपयोग किए जाने वाले नामों को एक-दूसरे के साथ टकराव नहीं किया जा सकता है। टेम्पलेट्स के लिए नामस्थान की आवश्यकता है। तो टेम्पलेट मैनेजर, जो टेम्पलेट ऑब्जेक्ट्स के लिए एक कारखाना है, उचित टेम्पलेट स्रोत फ़ाइल का पता लगाने के लिए टेम्पलेट नाम और नामस्थान नाम की आवश्यकता है। यह नामस्थान विशेष नियंत्रक के वर्ग नाम से संबंधित है।

लेकिन, ज्यादातर मामलों में, प्रत्येक नियंत्रक अपने नामस्थान से टेम्पलेट का उपयोग करेगा और केवल अन्य नामस्थानों के दुर्लभ मामलों में होगा। इसलिए प्रत्येक कॉल में नेमस्पेस को टेम्पलेटमैनेजर :: getTemplate() पर प्रत्येक बार एक गड़बड़ होगी। यह बेहतर है कि नामस्थान वैकल्पिक है और डिफ़ॉल्ट ... नियंत्रक जो टेम्पलेटमैनेजर :: getTemplate() को कॉल करता है! और कॉलर को जानने के लिए यहां एक अच्छी जगह है।

बेशक कॉलर नियंत्रक स्वयं या उसके नाम को पैरामीटर के रूप में पारित कर सकता है, लेकिन यह नामस्थान नाम को पार करने से वास्तव में बहुत अलग नहीं है। यह किसी भी तरह से वैकल्पिक नहीं हो सकता है।

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

5

आप कॉलिंग ऑब्जेक्ट को खुद को

उदा। ": पुन: प्रयोज्य वस्तु उन्मुख सॉफ्टवेयर के तत्वों डिजाइन पैटर्न" एरिक गामा, एट अल द्वारा, पेज 278 पर चर्चा में "मध्यस्थ" संरचनात्मक तर्ज पर

class Foo 
{ 
    public function __construct() 
    { 
    $bar = new Bar(); 
    $bar->test($this); 
    } 
} 

class Bar 
{ 
    public function test() 
    { 
    } 
} 
$foo = new Foo(); 

मैं किताब से इस विचार आया।

पैटर्न का बिंदु वस्तुओं/वर्गों के समूह के बीच कई से अधिक कनेक्शनों की संख्या को कम करना है। आप मध्यस्थ वर्ग बनाते हैं कि उन सभी वर्गों को एक केंद्र के रूप में माना जाता है। इस तरह कक्षाओं को एक-दूसरे के बारे में जानने की आवश्यकता नहीं है। मध्यस्थ बातचीत को संभालता है। मध्यस्थों को कक्षाओं में बदलावों के बारे में सूचित करने के लिए, वे स्वयं को तर्क के रूप में पारित कर सकते हैं, या मध्यस्थ को "पर्यवेक्षक" पैटर्न का उपयोग करके कार्यान्वित किया जा सकता है।

2018 संपादित करें:

मैं कभी कभी इस तरह, ऊपर कोड के साथ इंटरफेस का उपयोग करें:

interface someInterface // many classes may implement this interface 
{ 
    public function giveMeBar(); 
} 

class Foo implements someInterface 
{ 
    public function __construct() 
    { 
    $bar = new Bar(); 
    $bar->test($this); 
    } 
    public function giveMeBar() { 
    return 'Bar'; 
    } 
} 
class Bar 
{ 
    public function test(someInterface $a) 
    { 
    echo $a->giveMeBar(); 
    } 
} 
$foo = new Foo(); // prints "Bar" 
+1

यह सबसे समझदार समाधान था जो मैं साथ भी आ सकता था। Debug_backtrace एक हैक की तरह प्रतीत होता है, और PHP में मुझे पता है कि कॉल स्टैक नेविगेट करने का कोई और तरीका नहीं है। – siliconrockstar

14

यहाँ है एक लाइनर समाधान

list(, $caller) = debug_backtrace(false, 2); 

PHP7 के रूप में यह काम नहीं करेगा दस्तावेज़ों के आधार पर: http://php.net/manual/en/function.list.php क्योंकि हमारे पास खाली गुण नहीं हैं, यहां एक छोटा अपडेट है:

list($childClass, $caller) = debug_backtrace(false, 2); 
+0

क्या आप लिखना नहीं चाहते हैं? ... सूची (, $ कॉलर) = debug_backtrace (झूठी, 2); // या यह समय बर्बाद है? – JxAxMxIxN

+0

@JxAxMxIxN यह एक उचित बिंदु है कुछ निष्पादन चक्रों को बचाएगा, बदलेगा। – infinity

+3

एक लाइनर पुरुषों से प्यार है। धन्यवाद – suarsenegger

0

इस समारोह debug_backtrace बिना काम करता है:

/* 
usage : 
some code... 
getRealCallClass(__FUNCTION__); 
some code... 
*/ 

function getRealCallClass($functionName) //Parameter value must always be __FUNCTION__ 
{ 
    try 
    { 
    throw new exception(); 
    } 
    catch(exception $e) 
    { 
    $trace = $e->getTrace(); 
    $bInfunction = false; 
    foreach($trace as $trace_piece) 
     { 
      if ($trace_piece['function'] == $functionName) 
      { 
      if (!$bInfunction) 
       $bInfunction = true; 
      } 
      elseif($bInfunction) //found !!! 
      { 
      return $trace_piece['class']; 
      } 
     } 
    } 
} 
+0

यह सबसे अच्छा तरीका नहीं है। –

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