कैसे RecursiveIteratorIterator
काम ?
PHP मैन्युअल में बहुत कुछ प्रलेखित या समझाया नहीं गया है। बीच क्या अंतर है IteratorIterator
और RecursiveIteratorIterator
?
कैसे RecursiveIteratorIterator
काम ?
PHP मैन्युअल में बहुत कुछ प्रलेखित या समझाया नहीं गया है। बीच क्या अंतर है IteratorIterator
और RecursiveIteratorIterator
?
RecursiveIteratorIterator
काम करता है, तो क्या आप पहले से ही समझ चुके हैं कि कैसे IteratorIterator
काम करता है? मेरा मतलब है कि यह मूल रूप से एक ही है, केवल इंटरफ़ेस जो कि दो द्वारा खपत होती है अलग है। और क्या आप कुछ उदाहरणों में अधिक रुचि रखते हैं या क्या आप अंतर्निहित सी कोड कार्यान्वयन के रूप को देखना चाहते हैं?
IteratorIterator
नक्शे Iterator
और IteratorAggregate
एक में Iterator
, जहां REcusiveIteratorIterator
पुनरावृत्ति के लिए प्रयोग किया जाता हैRecursiveIterator
जवाबों:
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
किसी भी पेड़ पर लूप के लिए अधिक विशिष्ट की आवश्यकता होती है ।Traversable
RecursiveIteratorIterator
RecursiveIterator
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
। यह SplFileInfo
pathname के बजाय pathname का नाम देना चाहिए । अंतिम कोड टुकड़ा फिर जैसा दिख सकता है:
$lines = new RecursiveTreeIterator(
new DiyRecursiveDecorator($dir)
);
$unicodeTreePrefix($lines);
echo "[$path]\n", implode("\n", iterator_to_array($lines));
परिशिष्ट$unicodeTreePrefix
में ये अंश शामिल हैं : डू इट योरसेल्फ: मेक द RecursiveTreeIterator
वर्क लाइन बाय लाइन। ।
RecursiveIteratorIterator
क्योंकि यह अन्य प्रकारों के साथ आम है लेकिन मैंने कुछ तकनीकी जानकारी दी कि यह वास्तव में कैसे काम करता है। मुझे लगता है कि उदाहरण अच्छी तरह से मतभेद दिखाते हैं: चलना का प्रकार दोनों के बीच मुख्य अंतर है। कोई विचार नहीं है अगर आप इसे खरीदने के प्रकार को खरीदते हैं तो आप इसे थोड़ा अलग तरीके से गढ़ते हैं लेकिन IMHO आसान नहीं है।
की क्या अंतर है
IteratorIterator
औरRecursiveIteratorIterator
?
इन दो पुनरावृत्तियों के बीच के अंतर को समझने के लिए, किसी को पहले इस्तेमाल किए गए नामकरण सम्मेलनों के बारे में थोड़ा समझना चाहिए और "पुनरावर्ती" पुनरावृत्तियों से हमारा मतलब है।
PHP में गैर-"पुनरावर्ती" पुनरावृत्तियाँ हैं, जैसे ArrayIterator
और FilesystemIterator
। वहाँ भी "पुनरावर्ती" जैसे iterators RecursiveArrayIterator
औरRecursiveDirectoryIterator
। उत्तरार्द्ध में उन्हें नीचे गिराए जाने के लिए सक्षम करने के तरीके हैं, पूर्व नहीं है।
जब इन पुनरावृत्तियों के उदाहरण अपने दम पर पाले जाते हैं, यहां तक कि पुनरावर्ती भी, मान केवल "शीर्ष" स्तर से आते हैं, भले ही किसी नेस्टेड सरणी या निर्देशिका में उप-निर्देशिकाओं के साथ लूपिंग हो।
पुनरावर्ती पुनरावर्ती पुनरावर्ती व्यवहार (के माध्यम से ) को लागू करते हैं hasChildren()
, getChildren()
लेकिन इसका शोषण नहीं करते हैं।
पुनरावर्ती पुनरावृत्तियों को "पुनरावर्ती" पुनरावृत्तियों के रूप में सोचना बेहतर हो सकता है, उनके पास पुनरावर्ती रूप से पुनरावृत्त होने की क्षमता है, लेकिन इनमें से किसी एक वर्ग के उदाहरण पर पुनरावृत्ति करने से ऐसा नहीं होगा। पुनरावर्ती व्यवहार का फायदा उठाने के लिए, पढ़ना जारी रखें।
यह वह जगह है जहाँ RecursiveIteratorIterator
खेलने के लिए आता है। इसे "पुनरावर्ती" पुनरावृत्तियों को इस तरह से कॉल करने का ज्ञान है जैसे कि एक सामान्य, फ्लैट, लूप में संरचना में नीचे ड्रिल करने के लिए। यह पुनरावर्ती व्यवहार को कार्य में लगाता है। यह अनिवार्य रूप से इट्रेटर में प्रत्येक मूल्यों पर कदम रखने का काम करता है, यह देखने के लिए कि क्या "बच्चों" को पुनरावृत्ति करना है या नहीं, और बच्चों के उन संग्रह में से और बाहर कदम रखना है। आप उदाहरण के लिए RecursiveIteratorIterator
एक फ़ॉर्च में चिपके रहते हैं , और यह संरचना में गोता लगाता है ताकि आपके पास न हो।
यदि RecursiveIteratorIterator
उपयोग नहीं किया गया था, तो आपको पुनरावर्ती व्यवहार का फायदा उठाने के लिए अपने स्वयं के पुनरावर्ती छोरों को लिखना होगा, "पुनरावर्ती" पुनरावृत्तियों के खिलाफ जाँच करना hasChildren()
और उपयोग करना getChildren()
।
तो यह एक संक्षिप्त अवलोकन है RecursiveIteratorIterator
, यह कैसे अलग है IteratorIterator
? खैर, आप मूल रूप से एक ही तरह का प्रश्न पूछ रहे हैं कि बिल्ली के बच्चे और पेड़ में क्या अंतर है? सिर्फ इसलिए कि दोनों एक ही विश्वकोश (या पुनरावृत्तियों के लिए मैनुअल) में दिखाई देते हैं, इसका मतलब यह नहीं है कि आपको दोनों के बीच भ्रमित होना चाहिए।
का काम IteratorIterator
किसी भी Traversable
वस्तु को लेना है , और इसे इस तरह लपेटना है कि यह Iterator
इंटरफ़ेस को संतुष्ट करता है। इसके लिए एक उपयोग इसके बाद गैर-इट्रेटर ऑब्जेक्ट पर पुनरावृत्त-विशिष्ट व्यवहार को लागू करने में सक्षम है।
एक व्यावहारिक उदाहरण देने के लिए, DatePeriod
वर्ग है, Traversable
लेकिन नहीं Iterator
। जैसे, हम इसके मूल्यों पर लूप कर सकते हैं foreach()
लेकिन अन्य चीजों को नहीं कर सकते हैं जिन्हें हम आमतौर पर एक पुनरावृत्त के साथ करेंगे, जैसे कि फ़िल्टरिंग।
TASK : अगले चार सप्ताह के सोमवार, बुधवार और शुक्रवार को लूप करें।
हां, यह लूप के भीतर और उपयोग करने foreach
पर तुच्छ है ; लेकिन यह इस उदाहरण की बात नहीं है!DatePeriod
if()
$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
("पुनरावर्ती" पुनरावृत्ति) से अधिक पुनरावृत्ति के लिए , उपलब्ध होने वाले पुनरावर्ती व्यवहार का शोषण करता है।
IteratorIterator
Iterator
गैर-पुनरावृत्त, Traversable
वस्तुओं पर व्यवहार लागू करने के लिए है ।
IteratorIterator
लिए केवल रैखिक प्रकार का मानक मानक नहीं है Traversable
? जिनका उपयोग इसके बिना किया जा सकता है, foreach
वैसे ही? और आगे भी, RecursiveIterator
हमेशा एक Traversable
नहीं है और इसलिए न केवल "IteratorIterator
बल्कि RecursiveIteratorIterator
हमेशा गैर-इटरेटर, ट्रैवर्सेबल ऑब्जेक्ट्स के लिए व्यवहार लागू करने के लिए Iterator
" ? (मैं अब कहूंगा foreach
कि कंटेनर ऑब्जेक्ट्स पर इट्रेटर ऑब्जेक्ट के माध्यम से पुनरावृत्ति का प्रकार लागू होता है जो एक इट्रेटर-प्रकार इंटरफ़ेस को लागू करते हैं ताकि ये इटरेटर-कंटेनर-ऑब्जेक्ट, हमेशा हो Traversable
)
IteratorIterator
एक ऐसा वर्ग है जो Traversable
वस्तुओं को लपेटने के बारे में है Iterator
। और कुछ नहीं । आपको यह शब्द अधिक आम तौर पर लागू होता है।
Recursive
में RecursiveIterator
, व्यवहार का तात्पर्य जबकि एक अधिक उपयुक्त नाम है जो क्षमता का वर्णन है, जैसे हो गया होता RecursibleIterator
।
जब उपयोग किया जाता है 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
से अपने आंतरिक पुनरावृत्ति चलता है की एक संपत्ति है।
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