PHP में RecursiveIteratorIterator कैसे काम करता है?


88

कैसे RecursiveIteratorIterator काम ?

PHP मैन्युअल में बहुत कुछ प्रलेखित या समझाया नहीं गया है। बीच क्या अंतर है IteratorIteratorऔर RecursiveIteratorIterator?


2
वहाँ पर एक उदाहरण है php.net/manual/en/recursiveiteratoriterator.construct.php और वहाँ पर भी एक परिचय है php.net/manual/en/class.iteratoriterator.php - आप कृपया वास्तव में क्या आप मुसीबत समझ है का कहना है । इसे आसान बनाने के लिए मैनुअल में क्या होना चाहिए?
— गॉर्डन

1
यदि आप पूछते हैं कि कैसे RecursiveIteratorIteratorकाम करता है, तो क्या आप पहले से ही समझ चुके हैं कि कैसे IteratorIteratorकाम करता है? मेरा मतलब है कि यह मूल रूप से एक ही है, केवल इंटरफ़ेस जो कि दो द्वारा खपत होती है अलग है। और क्या आप कुछ उदाहरणों में अधिक रुचि रखते हैं या क्या आप अंतर्निहित सी कोड कार्यान्वयन के रूप को देखना चाहते हैं?
— हकर्रे

@Gordon मुझे यकीन नहीं था कि एकल फ़ॉरेस्ट लूप पेड़ की संरचना में सभी तत्वों को कैसे पार कर सकता है
— 17

@ अक्षरा अब मैं सभी इंटरफेसेस के साथ-साथ स्प्ल इंटरफेस और इट्रेटर इंप्लीमेंटेशन में अध्ययन करने की कोशिश कर रही हूं। मुझे यह जानने में दिलचस्पी थी कि यह कुछ उदाहरणों के साथ फॉर्च लूप के साथ पृष्ठभूमि में कैसे काम करता है।
— वारुग

@ खाकरे वे दोनों बहुत अलग हैं। IteratorIteratorनक्शे Iteratorऔर IteratorAggregateएक में Iterator, जहां REcusiveIteratorIteratorपुनरावृत्ति के लिए प्रयोग किया जाता हैRecursiveIterator
— एडम

जवाबों:


249

RecursiveIteratorIteratorएक ठोस Iteratorकार्यान्वयन ट्री ट्रैवर्सल है । यह एक प्रोग्रामर को एक कंटेनर ऑब्जेक्ट को पार करने में सक्षम बनाता है जो RecursiveIteratorइंटरफ़ेस को लागू करता है, विकिपीडिया में सामान्य सिद्धांतों, प्रकार, शब्दार्थ और पुनरावृत्तियों के पैटर्न के लिए Iterator देखें।

IteratorIteratorजिसके अंतर Iteratorमें रेखीय क्रम (और Traversableइसके निर्माता में किसी भी प्रकार को स्वीकार करने में डिफ़ॉल्ट रूप से) के रूप में एक ठोस कार्यान्वयन वस्तु ट्रैवर्सल है , वस्तुओं के RecursiveIteratorIteratorएक ऑर्डर किए गए पेड़ में सभी नोड्स पर लूपिंग की अनुमति देता है और इसके निर्माता एक लेता है RecursiveIterator।

संक्षेप में: RecursiveIteratorIteratorआप एक पेड़ पर लूप की अनुमति देता है,IteratorIterator पर लूप करने की अनुमति देता है आपको एक सूची पर लूप करने की अनुमति देता है। मैं दिखाता हूं कि जल्द ही नीचे कुछ कोड उदाहरण हैं।

तकनीकी रूप से यह सभी नोड्स के बच्चों (यदि कोई है) को ट्रेस करके रैखिकता से बाहर निकलकर काम करता है। यह संभव है क्योंकि परिभाषा के अनुसार एक नोड के सभी बच्चे फिर से एक हैं RecursiveIterator। Iteratorतब टॉपवेल आंतरिक रूप RecursiveIteratorसे अपनी गहराई से अलग-अलग एस Iteratorको हटाता है और ट्रैवर्सल के लिए वर्तमान सक्रिय उप के लिए एक संकेतक रखता है ।

यह एक पेड़ के सभी नोड्स का दौरा करने की अनुमति देता है।

अंतर्निहित सिद्धांत इसके साथ समान हैं IteratorIterator: एक इंटरफ़ेस पुनरावृत्ति के प्रकार को निर्दिष्ट करता है और आधार पुनरावृत्ति वर्ग इन शब्दार्थों का कार्यान्वयन है। नीचे दिए गए उदाहरणों के साथ तुलना करें, foreachआपके साथ रैखिक लूपिंग के लिए आम तौर पर कार्यान्वयन विवरणों के बारे में अधिक नहीं सोचते हैं जब तक कि आपको एक नया परिभाषित करने की आवश्यकता न हो Iterator(जैसे जब कुछ ठोस प्रकार खुद को लागू नहीं करता है Traversable)।

पुनरावर्ती ट्रैवर्सल के लिए - जब तक कि आप एक पूर्व-परिभाषित का उपयोग नहीं करते हैं, जिसमें पहले से Traversalही पुनरावर्ती ट्रैवर्सल पुनरावृत्ति है - आपको आमतौर पर मौजूदा पुनरावृत्ति को तुरंत हटाने की आवश्यकता होती है RecursiveIteratorIteratorया यहां तक ​​कि एक पुनरावर्ती ट्रावर्सल पुनरावृत्ति भी लिखना Traversableपड़ता है जो कि इस प्रकार के ट्रैवर्सल पुनरावृत्ति के साथ आपका अपना है foreach।

युक्ति: आपने संभवतः एक या दूसरे को स्वयं लागू नहीं किया है, इसलिए हो सकता है कि आपके पास उनके मतभेदों के व्यावहारिक अनुभव के लिए कुछ करने लायक हो। आपको उत्तर के अंत में एक DIY सुझाव मिलता है।

संक्षेप में तकनीकी अंतर:

  • जबकि रैखिक ट्रैवर्सल के लिए IteratorIteratorकिसी भी पेड़ पर लूप के लिए अधिक विशिष्ट की आवश्यकता होती है ।TraversableRecursiveIteratorIteratorRecursiveIterator
  • जहां IteratorIteratorइसके Iteratorमाध्यम से मुख्य उजागर होता है getInnerIerator(), RecursiveIteratorIteratorवर्तमान सक्रिय उप- Iteratorकेवल उस पद्धति के माध्यम से प्रदान करता है ।
  • जबकि IteratorIteratorमाता-पिता या बच्चों जैसी किसी भी चीज़ के बारे में पूरी तरह से जानकारी नहीं है, साथ RecursiveIteratorIteratorही यह भी जानती है कि बच्चों को कैसे प्राप्त किया जाए।
  • IteratorIteratorपुनरावृत्तियों के ढेर की आवश्यकता नहीं है, RecursiveIteratorIteratorइस तरह के एक स्टैक है और सक्रिय उप-इटेटर को जानता है।
  • IteratorIteratorलीनियरिटी और कोई विकल्प नहीं होने के कारण इसका ऑर्डर कहां है, RecursiveIteratorIteratorआगे के ट्रैवर्सल के लिए एक विकल्प है और प्रत्येक नोड ( मोड केRecursiveIteratorIterator माध्यम से तय किए गए) के अनुसार तय करने की आवश्यकता है ।
  • RecursiveIteratorIteratorसे अधिक विधियाँ हैं IteratorIterator।

संक्षेप में: RecursiveIteratorएक ठोस प्रकार का पुनरावृत्ति (एक पेड़ पर लूपिंग) है जो अपने स्वयं के पुनरावृत्तियों पर काम करता है, अर्थात् RecursiveIterator। यह उसी अंतर्निहित सिद्धांत के साथ है IteratorIerator, लेकिन पुनरावृत्ति का प्रकार अलग है (रैखिक क्रम)।

आदर्श रूप से आप अपना सेट भी बना सकते हैं। केवल आवश्यक यह है कि आपका पुनरावृत्ति लागू Traversableहो Iteratorया जिसके माध्यम से संभव हो IteratorAggregate। तब आप इसका उपयोग कर सकते हैं foreach। उदाहरण के लिए कुछ प्रकार के टर्नरी ट्री ट्रैवर्सल पुनरावर्ती पुनरावृत्ति वस्तु के साथ कंटेनर वस्तु (ओं) के लिए पुनरावृति इंटरफ़ेस के साथ।


आइए कुछ वास्तविक जीवन के उदाहरणों की समीक्षा करें जो कि अमूर्त नहीं हैं। इंटरफेस, कंक्रीट पुनरावृत्तियों, कंटेनर ऑब्जेक्ट्स और पुनरावृत्ति शब्दार्थ के बीच यह शायद एक बुरा विचार नहीं है।

एक उदाहरण के रूप में एक निर्देशिका लिस्टिंग ले लो। विचार करें कि आपको डिस्क पर निम्न फ़ाइल और निर्देशिका ट्री मिला है:

निर्देशिका ट्री

जबकि लीनियर ऑर्डर के साथ एक पुनरावृत्ति केवल टॉपलेवर फ़ोल्डर और फ़ाइलों (एक एकल निर्देशिका सूची) पर पार कर जाता है, पुनरावर्ती पुनरावर्तक सबफ़ोल्डर्स के माध्यम से भी पता लगाता है और सभी फ़ोल्डर्स और फ़ाइलों को सूचीबद्ध करता है (एक निर्देशिका जो इसके उपनिर्देशिकाओं की लिस्टिंग के साथ सूचीबद्ध होती है):

Non-Recursive        Recursive
=============        =========

   [tree]            [tree]
    ├ dirA            ├ dirA
    └ fileA           │ ├ dirB
                      │ │ └ fileD
                      │ ├ fileB
                      │ └ fileC
                      └ fileA

आप आसानी से इसकी तुलना कर सकते हैं IteratorIteratorजिसके साथ डायरेक्टरी ट्री को ट्रेस करने के लिए कोई पुनरावृत्ति नहीं होती है। और RecursiveIteratorIteratorजो रिकर्सिव लिस्टिंग शो के रूप में पेड़ में फैल सकता है।

एक साथ पहली बार एक बहुत ही बुनियादी उदाहरण पर DirectoryIteratorकि लागू करता Traversableहै जो की अनुमति देता है foreachके लिए पुनरावृति इस पर:

$path = 'tree';
$dir  = new DirectoryIterator($path);

echo "[$path]\n";
foreach ($dir as $file) {
    echo " ├ $file\n";
}

इसके बाद के संस्करण की संरचना के लिए अनुकरणीय आउटपुट है:

[tree]
 ├ .
 ├ ..
 ├ dirA
 ├ fileA

जैसा कि आप देख रहे हैं यह अभी तक उपयोग नहीं कर रहा है IteratorIteratorया RecursiveIteratorIterator। इसके बजाय यह सिर्फ इंटरफ़ेस foreachपर संचालित होता Traversableहै।

जैसा foreachकि डिफ़ॉल्ट रूप से केवल रैखिक क्रम नामक पुनरावृति का प्रकार जानता है, हम स्पष्ट रूप से पुनरावृत्ति के प्रकार को निर्दिष्ट करना चाह सकते हैं। पहली नज़र में यह बहुत अधिक क्रियात्मक लग सकता है, लेकिन प्रदर्शन के उद्देश्य (और RecursiveIteratorIteratorबाद में अधिक अंतर के साथ अंतर बनाने के लिए ), यह रैखिक प्रकार का विवरण निर्दिष्ट करता है IteratorIteratorजो निर्देशिका लिस्टिंग के लिए पुनरावृति के प्रकार को स्पष्ट रूप से निर्दिष्ट करता है :

$files = new IteratorIterator($dir);

echo "[$path]\n";
foreach ($files as $file) {
    echo " ├ $file\n";
}

यह उदाहरण पहले वाले के साथ लगभग समान है, अंतर यह है कि $filesअब इसके लिए एक IteratorIteratorप्रकार का पुनरावृत्ति है Traversable $dir:

$files = new IteratorIterator($dir);

हमेशा की तरह पुनरावृति का कार्य foreachनिम्न द्वारा किया जाता है :

foreach ($files as $file) {

आउटपुट बिल्कुल वैसा ही है। तो अलग क्या है? अलग वस्तु का उपयोग किया जाता है foreach। पहले उदाहरण में यह एक DirectoryIteratorदूसरे उदाहरण में यह है IteratorIterator। इससे पता चलता है कि लचीले चलने वालों के पास है: आप उन्हें एक दूसरे के साथ बदल सकते हैं, अंदर कोड foreachकेवल अपेक्षा के अनुरूप काम करना जारी रखते हैं।

उपनिर्देशिका सहित पूरी सूची प्राप्त करने के लिए शुरू करते हैं।

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

हम जानते हैं कि हमें पहले स्तर पर ही नहीं, पूरे पेड़ पर चढ़ने की जरूरत है। एक साधारण के साथ कि काम करवाने के लिए foreachहम इटरेटर एक अलग प्रकार की जरूरत है: RecursiveIteratorIterator। और वह केवल उन कंटेनर ऑब्जेक्ट्स पर पुनरावृति कर सकता है जिनके पास RecursiveIteratorइंटरफ़ेस है ।

इंटरफ़ेस एक अनुबंध है। इसे लागू करने वाले किसी भी वर्ग को एक साथ उपयोग किया जा सकता है RecursiveIteratorIterator। इस तरह के एक वर्ग का एक उदाहरण है RecursiveDirectoryIterator, जो पुनरावर्ती संस्करण की तरह कुछ है DirectoryIterator।

आइ-वर्ड के साथ कोई अन्य वाक्य लिखने से पहले एक पहला कोड उदाहरण देखें:

$dir  = new RecursiveDirectoryIterator($path);

echo "[$path]\n";
foreach ($dir as $file) {
    echo " ├ $file\n";
}

यह तीसरा उदाहरण पहले वाले के साथ लगभग समान है, हालांकि यह कुछ अलग आउटपुट बनाता है:

[tree]
 ├ tree\.
 ├ tree\..
 ├ tree\dirA
 ├ tree\fileA

ठीक है, अलग नहीं है, फ़ाइल नाम में अब पथनाम शामिल है, लेकिन बाकी समान दिखता है।

जैसा कि उदाहरण से पता चलता है, यहां तक ​​कि निर्देशिका ऑब्जेक्ट पहले से ही RecursiveIteratorइंटरफ़ेस की नकल करता है, यह अभी तक foreachपूरी निर्देशिका ट्री को पार करने के लिए पर्याप्त नहीं है । यह वह जगह है जहाँ RecursiveIteratorIteratorकार्रवाई में आता है। उदाहरण 4 दिखाता है कि कैसे:

$files = new RecursiveIteratorIterator($dir);

echo "[$path]\n";
foreach ($files as $file) {
    echo " ├ $file\n";
}

RecursiveIteratorIteratorकेवल पिछले $dirऑब्जेक्ट के बजाय का उपयोग करके foreachसभी फ़ाइलों और निर्देशिकाओं को एक पुनरावर्ती तरीके से पार करना होगा । यह तब सभी फाइलों को सूचीबद्ध करता है, जैसा कि ऑब्जेक्ट पुनरावृत्ति का प्रकार अब निर्दिष्ट किया गया है:

[tree]
 ├ tree\.
 ├ tree\..
 ├ tree\dirA\.
 ├ tree\dirA\..
 ├ tree\dirA\dirB\.
 ├ tree\dirA\dirB\..
 ├ tree\dirA\dirB\fileD
 ├ tree\dirA\fileB
 ├ tree\dirA\fileC
 ├ tree\fileA

यह पहले से ही फ्लैट और ट्री ट्रैवर्सल के बीच के अंतर को प्रदर्शित करना चाहिए। RecursiveIteratorIteratorतत्वों की सूची के रूप में किसी भी पेड़ की तरह संरचना पार करने में सक्षम है। चूँकि अधिक जानकारी होती है (जैसा कि वर्तमान में पुनरावृति जिस स्तर पर होती है), उस पर पुनरावृति करते हुए पुनरावृत्त वस्तु तक पहुँचना संभव है और उदाहरण के लिए आउटपुट को इंडेंट करें:

echo "[$path]\n";
foreach ($files as $file) {
    $indent = str_repeat('   ', $files->getDepth());
    echo $indent, " ├ $file\n";
}

और उदाहरण 5 का आउटपुट :

[tree]
 ├ tree\.
 ├ tree\..
    ├ tree\dirA\.
    ├ tree\dirA\..
       ├ tree\dirA\dirB\.
       ├ tree\dirA\dirB\..
       ├ tree\dirA\dirB\fileD
    ├ tree\dirA\fileB
    ├ tree\dirA\fileC
 ├ tree\fileA

यकीन है कि यह एक सौंदर्य प्रतियोगिता नहीं जीतता है, लेकिन यह दर्शाता है कि पुनरावर्ती पुनरावृत्ति के साथ कुंजी और मूल्य के रैखिक क्रम से अधिक जानकारी उपलब्ध है । यहां तक ​​कि foreachकेवल इस तरह की रैखिकता व्यक्त कर सकते हैं, इट्रेटर तक पहुंचने से ही अधिक जानकारी प्राप्त करने की अनुमति मिलती है।

मेटा-जानकारी के समान ही विभिन्न तरीके भी संभव हैं कि पेड़ को कैसे उतारा जाए और इसलिए आउटपुट का आदेश दिया जाए। यह मोड हैRecursiveIteratorIterator और इसे कंस्ट्रक्टर के साथ सेट किया जा सकता है।

अगला उदाहरण RecursiveDirectoryIteratorडॉट प्रविष्टियों को हटाने के लिए बताएगा ( .और ..) क्योंकि हमें उनकी आवश्यकता नहीं है। लेकिन मूल तत्व (उपनिर्देशिका) को पहले लेने के लिए रिकर्सन मोड भी बदला जाएगा (SELF_FIRST ) बच्चों से उप-पाठ में फाइलें और उप-उपखंड :

$dir  = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST);

echo "[$path]\n";
foreach ($files as $file) {
    $indent = str_repeat('   ', $files->getDepth());
    echo $indent, " ├ $file\n";
}

आउटपुट अब उपनिर्देशिका प्रविष्टियों को ठीक से सूचीबद्ध दिखाता है, यदि आप पिछले आउटपुट से तुलना करते हैं जो वहां नहीं थे:

[tree]
 ├ tree\dirA
    ├ tree\dirA\dirB
       ├ tree\dirA\dirB\fileD
    ├ tree\dirA\fileB
    ├ tree\dirA\fileC
 ├ tree\fileA

पुनरावृत्ति मोड इसलिए नियंत्रित करता है कि क्या और कब पेड़ में एक ब्राच या पत्ती वापस आती है, निर्देशिका उदाहरण के लिए:

  • LEAVES_ONLY (डिफ़ॉल्ट): केवल सूची फ़ाइलें, कोई निर्देशिका नहीं।
  • SELF_FIRST (ऊपर): सूची निर्देशिका और फिर वहां फाइलें।
  • CHILD_FIRST (w / o उदाहरण): पहले उपनिर्देशिका में फ़ाइलों की सूची, फिर निर्देशिका।

दो अन्य मोड के साथ उदाहरण 5 का आउटपुट :

  LEAVES_ONLY                           CHILD_FIRST

  [tree]                                [tree]
         ├ tree\dirA\dirB\fileD                ├ tree\dirA\dirB\fileD
      ├ tree\dirA\fileB                     ├ tree\dirA\dirB
      ├ tree\dirA\fileC                     ├ tree\dirA\fileB
   ├ tree\fileA                             ├ tree\dirA\fileC
                                        ├ tree\dirA
                                        ├ tree\fileA

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

मुझे लगता है कि ये एक उत्तर के लिए पर्याप्त उदाहरण हैं। आप इस जिस्ट में अच्छी दिखने वाली अस्सी-पेड़ों को प्रदर्शित करने के लिए पूर्ण स्रोत-कोड के साथ-साथ एक उदाहरण पा सकते हैं: https://gist.github.com/3599532

यह अपने आप करो:RecursiveTreeIterator लाइन से काम लाइन बनाओ ।

उदाहरण 5 ने प्रदर्शित किया कि पुनरावृत्त के राज्य के बारे में मेटा-जानकारी उपलब्ध है। हालाँकि, इसे उद्देश्यपूर्ण रूप से पुनरावृति के भीतर प्रदर्शित किया गया था foreach। वास्तविक जीवन में यह स्वाभाविक रूप से अंदर होता है RecursiveIterator।

एक बेहतर उदाहरण यह है RecursiveTreeIterator, यह इंडेंटिंग, उपसर्ग और इतने पर ध्यान रखता है। निम्नलिखित कोड टुकड़ा देखें:

$dir   = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$lines = new RecursiveTreeIterator($dir);
$unicodeTreePrefix($lines);
echo "[$path]\n", implode("\n", iterator_to_array($lines));

RecursiveTreeIteratorलाइन द्वारा काम लाइन करने का इरादा है, उत्पादन बहुत सीधा एक छोटी सी समस्या के साथ आगे है:

[tree]
 ├ tree\dirA
 │ ├ tree\dirA\dirB
 │ │ └ tree\dirA\dirB\fileD
 │ ├ tree\dirA\fileB
 │ └ tree\dirA\fileC
 └ tree\fileA

जब RecursiveDirectoryIteratorइसके साथ संयोजन में उपयोग किया जाता है, तो यह पूरे पथनाम को प्रदर्शित करता है, न कि केवल फ़ाइल नाम के साथ। बाकी अच्छा लग रहा है। इसका कारण यह है कि फ़ाइल-नाम जनरेट किए जाते हैं SplFileInfo। उन्हें इसके बदले बेसन के रूप में प्रदर्शित किया जाना चाहिए। वांछित आउटपुट निम्नलिखित है:

/// Solved ///

[tree]
 ├ dirA
 │ ├ dirB
 │ │ └ fileD
 │ ├ fileB
 │ └ fileC
 └ fileA

एक डेकोरेटर वर्ग बनाएं जिसका उपयोग RecursiveTreeIteratorइसके बजाय किया जा सकता है RecursiveDirectoryIterator। यह SplFileInfopathname के बजाय pathname का नाम देना चाहिए । अंतिम कोड टुकड़ा फिर जैसा दिख सकता है:

$lines = new RecursiveTreeIterator(
    new DiyRecursiveDecorator($dir)
);
$unicodeTreePrefix($lines);
echo "[$path]\n", implode("\n", iterator_to_array($lines));

परिशिष्ट$unicodeTreePrefix में ये अंश शामिल हैं : डू इट योरसेल्फ: मेक द RecursiveTreeIteratorवर्क लाइन बाय लाइन। ।


यह सवालों के जवाब नहीं देता है, इसमें तथ्यात्मक त्रुटियां हैं और जब आप पुनरावृति को अनुकूलित करने के लिए आगे बढ़ते हैं तो कोर बिंदुओं को याद करते हैं। सब के सब, यह एक विषय पर इनाम पाने के लिए एक खराब प्रयास की तरह दिखता है, जिसके बारे में आपको ज्यादा जानकारी नहीं है या, यदि आप करते हैं, तो सामने आए सवालों के जवाब में आसव नहीं कर सकते।
— सलातो

2
खैर जो मेरे "क्यों" सवाल का जवाब नहीं देता है, आप बस ज्यादा कुछ कहे बिना अधिक शब्द बनाते हैं। शायद आप वास्तव में एक त्रुटि के साथ शुरू करते हैं जो मायने रखता है? इसे इंगित करें, इसे अपना रहस्य न रखें।
— हैकर 14

बहुत पहला वाक्य गलत है: "RecursiveIteratorIterator एक IteratorIterator है जो समर्थन करता है ...", यह सच नहीं है।
— सलात

1
@ सालाथे: आप अपनी प्रतिक्रिया के लिए टैंक। मैंने इसे स्वीकार करने का उत्तर संपादित किया। पहला वाक्य वास्तव में गलत और अधूरा था। मैंने अभी भी ठोस कार्यान्वयन विवरणों को छोड़ दिया है RecursiveIteratorIteratorक्योंकि यह अन्य प्रकारों के साथ आम है लेकिन मैंने कुछ तकनीकी जानकारी दी कि यह वास्तव में कैसे काम करता है। मुझे लगता है कि उदाहरण अच्छी तरह से मतभेद दिखाते हैं: चलना का प्रकार दोनों के बीच मुख्य अंतर है। कोई विचार नहीं है अगर आप इसे खरीदने के प्रकार को खरीदते हैं तो आप इसे थोड़ा अलग तरीके से गढ़ते हैं लेकिन IMHO आसान नहीं है।
— हकरे

1
पहले भाग में कुछ हद तक सुधार हुआ है, लेकिन एक बार जब आप उदाहरणों पर आगे बढ़ना शुरू करते हैं तो यह अभी भी तथ्यात्मक अशुद्धि में बदल जाता है। यदि आपने क्षैतिज नियम में उत्तर को क्रॉप किया है, तो इसमें बहुत सुधार होगा।
— सलाथे

31

की क्या अंतर है IteratorIteratorऔर RecursiveIteratorIterator?

इन दो पुनरावृत्तियों के बीच के अंतर को समझने के लिए, किसी को पहले इस्तेमाल किए गए नामकरण सम्मेलनों के बारे में थोड़ा समझना चाहिए और "पुनरावर्ती" पुनरावृत्तियों से हमारा मतलब है।

पुनरावर्ती और गैर-पुनरावर्ती पुनरावृत्तियों

PHP में गैर-"पुनरावर्ती" पुनरावृत्तियाँ हैं, जैसे ArrayIteratorऔर FilesystemIterator। वहाँ भी "पुनरावर्ती" जैसे iterators RecursiveArrayIteratorऔरRecursiveDirectoryIterator । उत्तरार्द्ध में उन्हें नीचे गिराए जाने के लिए सक्षम करने के तरीके हैं, पूर्व नहीं है।

जब इन पुनरावृत्तियों के उदाहरण अपने दम पर पाले जाते हैं, यहां तक ​​कि पुनरावर्ती भी, मान केवल "शीर्ष" स्तर से आते हैं, भले ही किसी नेस्टेड सरणी या निर्देशिका में उप-निर्देशिकाओं के साथ लूपिंग हो।

पुनरावर्ती पुनरावर्ती पुनरावर्ती व्यवहार (के माध्यम से ) को लागू करते हैं hasChildren(), getChildren()लेकिन इसका शोषण नहीं करते हैं।

पुनरावर्ती पुनरावृत्तियों को "पुनरावर्ती" पुनरावृत्तियों के रूप में सोचना बेहतर हो सकता है, उनके पास पुनरावर्ती रूप से पुनरावृत्त होने की क्षमता है, लेकिन इनमें से किसी एक वर्ग के उदाहरण पर पुनरावृत्ति करने से ऐसा नहीं होगा। पुनरावर्ती व्यवहार का फायदा उठाने के लिए, पढ़ना जारी रखें।

RecursiveIteratorIterator

यह वह जगह है जहाँ RecursiveIteratorIteratorखेलने के लिए आता है। इसे "पुनरावर्ती" पुनरावृत्तियों को इस तरह से कॉल करने का ज्ञान है जैसे कि एक सामान्य, फ्लैट, लूप में संरचना में नीचे ड्रिल करने के लिए। यह पुनरावर्ती व्यवहार को कार्य में लगाता है। यह अनिवार्य रूप से इट्रेटर में प्रत्येक मूल्यों पर कदम रखने का काम करता है, यह देखने के लिए कि क्या "बच्चों" को पुनरावृत्ति करना है या नहीं, और बच्चों के उन संग्रह में से और बाहर कदम रखना है। आप उदाहरण के लिए RecursiveIteratorIteratorएक फ़ॉर्च में चिपके रहते हैं , और यह संरचना में गोता लगाता है ताकि आपके पास न हो।

यदि RecursiveIteratorIteratorउपयोग नहीं किया गया था, तो आपको पुनरावर्ती व्यवहार का फायदा उठाने के लिए अपने स्वयं के पुनरावर्ती छोरों को लिखना होगा, "पुनरावर्ती" पुनरावृत्तियों के खिलाफ जाँच करना hasChildren()और उपयोग करना getChildren()।

तो यह एक संक्षिप्त अवलोकन है RecursiveIteratorIterator, यह कैसे अलग है IteratorIterator? खैर, आप मूल रूप से एक ही तरह का प्रश्न पूछ रहे हैं कि बिल्ली के बच्चे और पेड़ में क्या अंतर है? सिर्फ इसलिए कि दोनों एक ही विश्वकोश (या पुनरावृत्तियों के लिए मैनुअल) में दिखाई देते हैं, इसका मतलब यह नहीं है कि आपको दोनों के बीच भ्रमित होना चाहिए।

IteratorIterator

का काम IteratorIteratorकिसी भी Traversableवस्तु को लेना है , और इसे इस तरह लपेटना है कि यह Iteratorइंटरफ़ेस को संतुष्ट करता है। इसके लिए एक उपयोग इसके बाद गैर-इट्रेटर ऑब्जेक्ट पर पुनरावृत्त-विशिष्ट व्यवहार को लागू करने में सक्षम है।

एक व्यावहारिक उदाहरण देने के लिए, DatePeriodवर्ग है, Traversableलेकिन नहीं Iterator। जैसे, हम इसके मूल्यों पर लूप कर सकते हैं foreach()लेकिन अन्य चीजों को नहीं कर सकते हैं जिन्हें हम आमतौर पर एक पुनरावृत्त के साथ करेंगे, जैसे कि फ़िल्टरिंग।

TASK : अगले चार सप्ताह के सोमवार, बुधवार और शुक्रवार को लूप करें।

हां, यह लूप के भीतर और उपयोग करने foreachपर तुच्छ है ; लेकिन यह इस उदाहरण की बात नहीं है!DatePeriodif()

$period = new DatePeriod(new DateTime, new DateInterval('P1D'), 28);
$dates  = new CallbackFilterIterator($period, function ($date) {
    return in_array($date->format('l'), array('Monday', 'Wednesday', 'Friday'));
});
foreach ($dates as $date) { … }

उपरोक्त स्निपेट काम नहीं करेगा क्योंकि CallbackFilterIteratorएक वर्ग के एक उदाहरण की अपेक्षा करता है Iteratorजो इंटरफ़ेस को लागू करता है, जो DatePeriodनहीं करता है। हालाँकि, चूंकि यह Traversableहम आसानी से उपयोग करके उस आवश्यकता को पूरा कर सकते हैं IteratorIterator।

$period = new IteratorIterator(new DatePeriod(…));

जैसा कि आप देख सकते हैं, यह कुछ भी नहीं करने के लिए पुनरावृति वर्गों और पुनरावृत्ति पर पुनरावृत्ति के साथ क्या करना है, और उसमें IteratorIteratorऔर के बीच अंतर निहित है RecursiveIteratorIterator।

सारांश

RecursiveIteraratorIteratorएक RecursiveIterator("पुनरावर्ती" पुनरावृत्ति) से अधिक पुनरावृत्ति के लिए , उपलब्ध होने वाले पुनरावर्ती व्यवहार का शोषण करता है।

IteratorIteratorIteratorगैर-पुनरावृत्त, Traversableवस्तुओं पर व्यवहार लागू करने के लिए है ।


क्या वस्तुओं के IteratorIteratorलिए केवल रैखिक प्रकार का मानक मानक नहीं है Traversable? जिनका उपयोग इसके बिना किया जा सकता है, foreachवैसे ही? और आगे भी, RecursiveIterator हमेशा एक Traversableनहीं है और इसलिए न केवल "IteratorIterator बल्कि RecursiveIteratorIteratorहमेशा गैर-इटरेटर, ट्रैवर्सेबल ऑब्जेक्ट्स के लिए व्यवहार लागू करने के लिए Iterator" ? (मैं अब कहूंगा foreachकि कंटेनर ऑब्जेक्ट्स पर इट्रेटर ऑब्जेक्ट के माध्यम से पुनरावृत्ति का प्रकार लागू होता है जो एक इट्रेटर-प्रकार इंटरफ़ेस को लागू करते हैं ताकि ये इटरेटर-कंटेनर-ऑब्जेक्ट, हमेशा हो Traversable)
— 22

जैसा कि मेरे उत्तर में कहा गया है, IteratorIteratorएक ऐसा वर्ग है जो Traversableवस्तुओं को लपेटने के बारे में है Iterator। और कुछ नहीं । आपको यह शब्द अधिक आम तौर पर लागू होता है।
— सलाथे

लगातार सूचनात्मक उत्तर। एक सवाल, RecursiveIteratorIterator भी वस्तुओं को लपेट नहीं करेगा ताकि वे भी Iterator व्यवहार तक पहुंच सकें? दोनों के बीच एकमात्र अंतर यह होगा कि RecursiveIteratorIterator ड्रिल कर सकता है, जबकि IteratorIterator नहीं कर सकता है?
— माइक पर्ससेल

@salathe, क्या आप जानते हैं कि पुनरावर्ती पुनरावर्तक (RecursiveDirectoryIterator) में हैशल्ड्रेन (), getChildren () व्यवहार क्यों नहीं है?
— एरू

7
"पुनरावर्ती" कहने के लिए +1। नाम एक लंबे समय के लिए भटक मुझे नेतृत्व क्योंकि Recursiveमें RecursiveIterator, व्यवहार का तात्पर्य जबकि एक अधिक उपयुक्त नाम है जो क्षमता का वर्णन है, जैसे हो गया होता RecursibleIterator।
— बकरी

0

जब उपयोग किया जाता है iterator_to_array(), RecursiveIteratorIteratorतो सभी मानों को खोजने के लिए पुन: सरणी चला जाएगा। इसका मतलब है कि यह मूल सरणी को समतल करेगा।

IteratorIterator मूल पदानुक्रमित संरचना रखेंगे।

यह उदाहरण आपको स्पष्ट रूप से अंतर दिखाएगा:

$array = array(
               'ford',
               'model' => 'F150',
               'color' => 'blue', 
               'options' => array('radio' => 'satellite')
               );

$recursiveIterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
var_dump(iterator_to_array($recursiveIterator, true));

$iterator = new IteratorIterator(new ArrayIterator($array));
var_dump(iterator_to_array($iterator,true));

यह पूरी तरह से भ्रामक है। new IteratorIterator(new ArrayIterator($array))के बराबर new ArrayIterator($array)है, अर्थात्, बाहरी IteratorIteratorकुछ नहीं कर रहा है। इसके अलावा, आउटपुट के चपटेपन का कोई लेना-देना नहीं है iterator_to_array- यह केवल इटरेटर को एक सरणी में परिवर्तित करता है। चपटा जिस तरह RecursiveArrayIteratorसे अपने आंतरिक पुनरावृत्ति चलता है की एक संपत्ति है।
— क्वोलोन प्रश्न

0

RecursiveDirectoryIterator यह पूरे pathname को प्रदर्शित करता है न कि केवल फ़ाइल नाम को। बाकी अच्छा लग रहा है। इसका कारण यह है कि फ़ाइल-नाम SplFileInfo द्वारा उत्पन्न किए जाते हैं। उन्हें इसके बदले बेसन के रूप में प्रदर्शित किया जाना चाहिए। वांछित आउटपुट निम्नलिखित है:

$path =__DIR__;
$dir = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($dir,RecursiveIteratorIterator::SELF_FIRST);
while ($files->valid()) {
    $file = $files->current();
    $filename = $file->getFilename();
    $deep = $files->getDepth();
    $indent = str_repeat('│ ', $deep);
    $files->next();
    $valid = $files->valid();
    if ($valid and ($files->getDepth() - 1 == $deep or $files->getDepth() == $deep)) {
        echo $indent, "├ $filename\n";
    } else {
        echo $indent, "└ $filename\n";
    }
}

उत्पादन:

tree
 ├ dirA
 │ ├ dirB
 │ │ └ fileD
 │ ├ fileB
 │ └ fileC
 └ fileA
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.