RecursiveIteratorIterator PHP'de nasıl çalışır?


89

Nasıl RecursiveIteratorIteratorçalışır?

PHP kılavuzunda çok fazla belgelenmiş veya açıklanmış hiçbir şey yoktur. Arasındaki fark nedir IteratorIteratorve RecursiveIteratorIterator?


2
php.net/manual/en/recursiveiteratoriterator.construct.php adresinde bir örnek var ve ayrıca php.net/manual/en/class.iteratoriterator.php adresinde bir Giriş var - lütfen tam olarak anlamakta zorlandığınız şeyi işaret eder misiniz . Kılavuzun anlaşılmasını kolaylaştırmak için neler içermesi gerekir?
Gordon

1
Nasıl RecursiveIteratorIteratorçalıştığını sorarsanız, nasıl çalıştığını zaten anladınız IteratorIteratormı? Demek istediğim, temelde aynı, sadece ikisi tarafından tüketilen arayüz farklı. Ve bazı örneklerle mi daha çok ilgileniyorsunuz yoksa temeldeki C kodu uygulamasının farkını mı görmek istiyorsunuz?
hakre

@Gordon, tek bir foreach döngüsünün ağaç yapısındaki tüm öğeleri nasıl geçebileceğinden emin
değildim

@hakra şimdi spl arabirimi ve yineleyici uygulamasının yanı sıra tüm yerleşik arabirimleri incelemeye çalışıyorum. bazı örneklerle arka planda forach döngüsü ile nasıl çalıştığını bilmek ilgimi çekti.
varuog

@hakre İkisi de aslında çok farklı. IteratorIteratorharitalar Iteratorve IteratorAggregatebir Iterator, REcusiveIteratorIteratortekrarlanabilir şekilde geçmek için kullanılan birRecursiveIterator
Adam

Yanıtlar:


253

RecursiveIteratorIteratorsomut bir Iteratoruygulama ağacı geçişidir . Bir programcının RecursiveIteratorarayüzü uygulayan bir konteyner nesnesini geçmesini sağlar, yineleyicilerin genel ilkeleri, türleri, anlambilim ve örüntüleri için Wikipedia'daki Yineleyiciye bakın.

Farkı ise hiç IteratorIteratorhangi bir betondur Iteratorlineer sırayla (ve varsayılan olarak her türlü kabul uygulayan nesne geçişi Traversableonun kurucu), RecursiveIteratorIteratorbir bütün düğümleri üzerinde döngü verir sipariş ağacın nesnelerin ve yapıcı bir sürer RecursiveIterator.

Kısaca: RecursiveIteratorIteratorbir ağaç IteratorIteratorüzerinde döngü yapmanıza, bir liste üzerinden döngü yapmanıza olanak tanır. Bunu yakında bazı kod örnekleriyle göstereceğim.

Teknik olarak bu, bir düğümün tüm çocuklarını (varsa) geçerek doğrusallığın dışına çıkarak çalışır. Bu mümkündür, çünkü tanım gereği bir düğümün tüm çocukları yine a'dır RecursiveIterator. Üst seviye Iteratordaha sonra farklı s'leri RecursiveIteratorderinliklerine göre dahili olarak istifler ve Iteratorgeçiş için geçerli aktif alt seviyeye bir işaretçi tutar .

Bu, bir ağacın tüm düğümlerini ziyaret etmeyi sağlar.

Temel ilkeler şununla aynıdır IteratorIterator: Bir arabirim yinelemenin türünü belirtir ve temel yineleme sınıfı bu anlambilimin uygulamasıdır. Aşağıdaki örneklerle karşılaştırın, doğrusal döngü için foreachsizinle normalde yeni bir tanımlamanız gerekmedikçe uygulama ayrıntılarını fazla düşünmeyin Iterator(örneğin, somut bir türün kendisi uygulanmadığında Traversable).

Özyinelemeli geçişi için - bir kullanmayan sürece öncesi tanımlı Traversalzaten özyinelemeli geçişi yineleme sahip olduğunu - normalde ihtiyaç mevcut örneğini RecursiveIteratorIteratoriterasyon hatta yazma bir özyinelemeli geçişi yineleme bir olduğunu Traversablekastetmek iterasyon ile bu tür olması için kendi foreach.

İpucu: Muhtemelen birini ya da diğerini kendiniz uygulamadınız, bu yüzden bu, aralarındaki farklılıklara ilişkin pratik deneyiminiz için yapmaya değer bir şey olabilir. Cevabın sonunda bir DIY önerisi buluyorsunuz.

Kısaca teknik farklılıklar:

  • Doğrusal geçiş için IteratorIteratorherhangi birini alırken , bir ağaç üzerinde döngü için daha spesifik bir ihtiyaç vardır .TraversableRecursiveIteratorIteratorRecursiveIterator
  • Burada IteratorIteratorana ortaya Iteratorile getInnerIerator(), RecursiveIteratorIteratormevcut aktif alt sağlar Iteratorancak bu yöntem ile.
  • İken IteratorIteratortamamen ebeveyn veya çocuk gibi her şeyin farkında değildir, RecursiveIteratorIteratoraynı zamanda almak ve travers çocuklar bilir.
  • IteratorIteratorbir yineleyici yığınına ihtiyaç duymaz RecursiveIteratorIterator, böyle bir yığını vardır ve aktif alt yineleyiciyi bilir.
  • Nerede IteratorIteratorlineer ve seçim nedeniyle siparişini sahiptir RecursiveIteratorIteratorileri kastetmek ve her düğüm başına karar vermek ihtiyaçları için seçeneği vardır (aracılığıyla karar mod başınaRecursiveIteratorIterator ).
  • RecursiveIteratorIteratordaha fazla yöntemi var IteratorIterator.

Özetlemek gerekirse: RecursiveIteratorkendi yineleyicileri üzerinde çalışan somut bir yineleme türüdür (bir ağaç üzerinde döngüdür) RecursiveIterator. Bu, temelde yatan ilke ile aynıdır IteratorIerator, ancak yineleme türü farklıdır (doğrusal sıra).

İdeal olarak kendi setinizi de oluşturabilirsiniz. Gerekli olan tek şey, yineleyicinizin veya Traversablearacılığıyla mümkün olanı gerçekleştirmesidir . O zaman kullanabilirsinizIteratorIteratorAggregateforeach . Örneğin, konteyner nesnesi (leri) için uygun yineleme arabirimi ile birlikte bir tür üçlü ağaç çapraz yinelemeli yineleme nesnesi.


O kadar soyut olmayan bazı gerçek hayattan örneklerle gözden geçirelim. Arayüzler, somut yineleyiciler, kapsayıcı nesneler ve yineleme semantiği arasında bu belki de o kadar da kötü bir fikir değil.

Örnek olarak bir dizin listesi alın. Diskte aşağıdaki dosya ve dizin ağacına sahip olduğunuzu düşünün:

Dizin Ağacı

Doğrusal sıraya sahip bir yineleyici, üst düzey klasör ve dosyalar üzerinde gezinirken (tek bir dizin listesi), yinelemeli yineleyici, alt klasörler arasında da gezinir ve tüm klasörleri ve dosyaları listeler (alt dizinlerinin listelerini içeren bir dizin listesi):

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

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

Bunu IteratorIterator, dizin ağacında gezinmek için hiçbir özyineleme yapmayanla kolayca karşılaştırabilirsiniz . VeRecursiveIteratorIterator Özyinelemeli listenin gösterdiği gibi ağaçtan geçebilir.

Bir ilk çok temel bir örnek de DirectoryIteratorbunu uygulayan Traversableverir foreachiçin yineleme üzerine:

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

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

Yukarıdaki dizin yapısı için örnek çıktı:

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

Gördüğünüz gibi bu henüz IteratorIteratorveya kullanmıyor RecursiveIteratorIterator. Bunun yerine sadece sadece kullanılarak foreachbu konuda faaliyetTraversable arayüzde .

Gibi foreachyalnızca doğrusal düzen adlı yineleme türünü bilen varsayılan olarak, biz açıkça yineleme türünü belirtmek isteyebilirsiniz. İlk bakışta çok ayrıntılı görünebilir, ancak gösterim amacıyla (ve RecursiveIteratorIteratordaha sonra daha görünür IteratorIteratorolması için), dizin listesi için yineleme türünü açıkça belirterek doğrusal yineleme türünü belirleyelim :

$files = new IteratorIterator($dir);

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

Bu örnek, ilkiyle neredeyse aynıdır , aradaki fark, $filesşu anda aşağıdakiler için bir IteratorIteratortür yineleme olmasıdır Traversable $dir:

$files = new IteratorIterator($dir);

Her zamanki gibi, yineleme eylemi aşağıdakiler tarafından gerçekleştirilir foreach:

foreach ($files as $file) {

Çıktı tamamen aynı. Öyleyse farklı olan nedir? İçinde kullanılan nesne farklıdır foreach. İlk örnekte bu, DirectoryIteratorikinci örnekte bir IteratorIterator. Bu, yineleyicilerin sahip olduğu esnekliği gösterir: Bunları birbirleriyle değiştirebilirsiniz, içindeki kodforeach beklendiği gibi çalışmaya devam eder.

Alt dizinler dahil tüm listeyi almaya başlayalım.

Şimdi yineleme türünü belirttiğimiz gibi, onu başka bir yineleme türüne değiştirmeyi düşünelim.

Şimdi sadece ilk seviyeyi değil, tüm ağacı geçmemiz gerektiğini biliyoruz. Bir basit olan bu işi sahip olmak foreachbiz Yineleyici farklı türde bir gerekir: RecursiveIteratorIterator. Ve bu, yalnızca arayüze sahip konteyner nesneleri üzerinde yineleme yapabilir.RecursiveIterator .

Arayüz bir sözleşmedir. Bunu uygulayan herhangi bir sınıf RecursiveIteratorIterator,. Böyle bir sınıfa örnek, ' RecursiveDirectoryIteratornin özyinelemeli varyantı gibi bir şeydir.DirectoryIterator .

I-word ile başka bir cümle yazmadan önce ilk kod örneğini görelim:

$dir  = new RecursiveDirectoryIterator($path);

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

Bu üçüncü örnek ilkiyle neredeyse aynıdır, ancak bazı farklı çıktılar yaratır:

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

Tamam, o kadar da farklı değil, dosya adı artık öndeki yol adını içeriyor, ancak geri kalanı da benzer görünüyor.

Örnekte gösterildiği gibi, dizin nesnesi zaten RecursiveIteratorarabirimi taklit etse bile , bu henüz foreachtüm dizin ağacını çapraz geçiş yapmak için yeterli değildir . İşte burada RecursiveIteratorIteratordevreye giriyor. Örnek 4 şunları göstermektedir:

$files = new RecursiveIteratorIterator($dir);

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

Kullanılması RecursiveIteratorIteratoryerine önceki bir $dirnesne yapacak foreachbir özyinelemeli şekilde tüm dosyaları ve dizinleri üzerinde hareket etmesi. Bu, daha sonra nesne yineleme türü şimdi belirtildiğinden tüm dosyaları listeler:

[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

Bu, düz ve ağaç geçişi arasındaki farkı zaten göstermelidir. RecursiveIteratorIteratorElemanlarının bir listesi olarak herhangi bir ağaç benzeri bir yapı çapraz edebilmektedir. Daha fazla bilgi olduğu için (yinelemenin o anda gerçekleştiği düzey gibi), üzerinde yineleyerek yineleyici nesneye erişmek ve örneğin çıktıyı girintilemek mümkündür:

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

Ve Örnek 5'in çıktısı :

[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

Elbette bu bir güzellik yarışmasını kazanmaz, ancak yinelemeli yinelemeyle, anahtar ve değerin doğrusal sırasından daha fazla bilgi bulunduğunu gösterir . Hatta foreachsadece bu tür bir doğrusallığı ifade edebilir, yineleyicinin kendisine erişmek daha fazla bilgi elde etmeyi sağlar.

Meta bilgiye benzer şekilde, ağacın üzerinden geçmenin ve dolayısıyla çıktıyı sipariş etmenin farklı yolları da vardır. Bu Mod arasındaRecursiveIteratorIterator ve yapıcı ile ayarlanabilir.

Bir sonraki örnek, ihtiyacımız olmadığı RecursiveDirectoryIteratoriçin nokta girişlerini ( .ve ..) kaldırmasını söyleyecektir . Ancak özyineleme modu, alt öğe (alt dizindeki SELF_FIRSTdosyalar ve alt dizinler) önce ( ) üst öğeyi (alt dizin) alacak şekilde değiştirilecektir :

$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";
}

Çıktı, artık orada olmayanlar önceki çıktıyla karşılaştırırsanız, alt dizin girişlerinin düzgün bir şekilde listelendiğini gösterir:

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

Bu nedenle özyineleme modu, dizin örneği için ağaçtaki bir köşeli ayraç veya yaprağın ne ve ne zaman döndürüleceğini kontrol eder:

  • LEAVES_ONLY (varsayılan): Yalnızca dosyaları listele, dizin yok.
  • SELF_FIRST (yukarıda): Dizini ve ardından içindeki dosyaları listeleyin.
  • CHILD_FIRST (örneksiz): Önce alt dizindeki dosyaları, ardından dizini listeleyin.

Örnek 5'in diğer iki modla çıktısı :

  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

Bunu standart geçişle karşılaştırdığınızda, tüm bunlar mevcut değildir. Bu nedenle özyinelemeli yineleme, kafanızı etrafına sarmanız gerektiğinde biraz daha karmaşıktır, ancak bir yineleyici gibi davrandığı için kullanımı kolaydır,foreach ve bitirdiniz.

Sanırım bunlar bir cevap için yeterli örnek. Tam kaynak kodunu ve güzel görünümlü ascii ağaçlarını gösteren bir örneği bu özette bulabilirsiniz: https://gist.github.com/3599532

Kendin Yap :RecursiveTreeIterator İş Satırını Satır Satır Yap .

Örnek 5 , yineleyicinin durumu hakkında meta bilgi mevcut olduğunu gösterdi. Bununla birlikte, bu bilinçli gösterilmiştir içindeforeach yineleme. Gerçek hayatta bu, doğal olarak RecursiveIterator.

Daha iyi bir örnek, RecursiveTreeIteratorgirinti, önek vb. İle ilgilenir. Aşağıdaki kod parçasına bakın:

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

RecursiveTreeIteratorÇizgi ile iş hattına amaçlanmaktadır çıkış oldukça yalındır bir küçük problem ile geçerli:

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

A ile birlikte kullanıldığında, RecursiveDirectoryIteratorsadece dosya adını değil, tüm yol adını görüntüler. Gerisi iyi görünüyor. Bunun nedeni, dosya adlarının SplFileInfo. Bunlar, bunun yerine temel adı olarak görüntülenmelidir. İstenen çıktı şu şekildedir:

/// Solved ///

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

İle kullanılabilecek bir dekoratör sınıf oluşturun RecursiveTreeIteratoryerine RecursiveDirectoryIterator. Yol SplFileInfoadı yerine akımın temel adını sağlamalıdır . Son kod parçası daha sonra şöyle görünebilir:

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

Bu parçalar $unicodeTreePrefix, Ek: Kendin Yap: RecursiveTreeIteratorİş Satırını Satır Satır Yapın'daki özün bir parçasıdır . .


Yinelemeyi özelleştirmeye geçtiğinizde, sorulan soruları yanıtlamaz, gerçek hatalar içerir ve temel noktaları gözden kaçırır. Sonuç olarak, hakkında çok fazla şey bilmediğiniz bir konuda ödül almak için kötü bir girişim gibi görünüyor ya da eğer öyleyse, sorulan sorulara bir cevap olarak damıtılamıyor.
56'da selamlama

2
Bu da benim "neden" sorumun cevabını vermiyor, fazla bir şey söylemeden sadece daha fazla kelime yapıyorsun. Belki de gerçekten önemli bir Hata ile başlarsınız? Göster, sır olarak saklamayın.
hakre

İlk cümle yanlıştır: "RecursiveIteratorIterator,… destekleyen bir Yineleyici Yineleyicidir", bu doğru değil.
02

1
@salathe: Geri bildiriminiz için size teşekkür ederim. Cevabı adreslemek için düzenledim. İlk cümle gerçekten yanlış ve eksikti. Somut uygulama ayrıntılarını hala dışarıda bıraktım RecursiveIteratorIteratorçünkü bu diğer türlerle ortaktır, ancak gerçekte nasıl çalıştığına dair bazı teknik bilgiler verdim. Bence örnekler de farklılıklar gösterir: yineleme türü olan ikisi arasındaki temel fark. Onu biraz farklı bir şekilde satın aldığınız yineleme türünü satın alırsanız hiçbir fikrim yok, ancak IMHO yinelemenin semantik türleriyle kolay değil.
hakre

1
İlk bölüm biraz geliştirildi, ancak örneklere geçmeye başladığınızda yine de gerçeklere dayalı yanlışlıklara dönüşüyor. Yanıtı yatay kuralda kırparsanız, çok daha iyi olacaktır.
03

32

Farkı nedir IteratorIteratorve RecursiveIteratorIterator?

Bu iki yineleyici arasındaki farkı anlamak için, önce kullanılan adlandırma kurallarını ve "özyinelemeli" yineleyicilerle ne demek istediğimizi biraz anlamak gerekir.

Yinelemeli ve yinelemeli olmayan yineleyiciler

PHP, ArrayIteratorve gibi "özyinelemeli" olmayan yineleyiciler içerir FilesystemIterator. Ayrıca RecursiveArrayIteratorve gibi "özyinelemeli" yineleyiciler de vardır RecursiveDirectoryIterator. İkincisi, derinlemesine derinlemesine araştırılmalarını sağlayan yöntemlere sahipken, ilki yoktur.

Bu yineleyicilerin örnekleri kendi başlarına döngü oluşturduğunda, özyinelemeli olanlar bile, alt dizinlere sahip iç içe geçmiş bir dizi veya dizin üzerinde döngü oluştursa bile, değerler yalnızca "üst" düzeyden gelir.

Özyinelemeli yineleyiciler özyinelemeli davranış (aracılığıyla , ) uygular ancak bundan yararlanmazlar .hasChildren()getChildren()

Yinelemeli yineleyicileri "yinelemeli" yineleyiciler olarak düşünmek daha iyi olabilir, yinelemeli yineleme yeteneğine sahiptirler, ancak bu sınıflardan birinin bir örneğini basitçe yinelemek bunu yapmayacaktır. Özyinelemeli davranıştan yararlanmak için okumaya devam edin.

RecursiveIteratorIterator

RecursiveIteratorIteratorOyun burada devreye giriyor. Normal, düz bir döngüde yapının derinliklerine inecek şekilde "tekrarlanabilir" yineleyicileri nasıl çağıracağına dair bilgiye sahiptir. Özyinelemeli davranışı eyleme geçirir. Esasen, yineleyicideki değerlerin her birinin üzerinden geçme, tekrarlanacak "çocuklar" olup olmadığına bakma ve bu çocuk koleksiyonlarına girip çıkma işini yapar. Bir örneğini RecursiveIteratorIteratorbir foreach'a yapıştırırsınız ve o yapının içine dalar, böylece sizin zorunda kalmazsınız.

Eğer RecursiveIteratorIteratorkullanılmamışsa, özyinelemeli davranıştan yararlanmak için kendi özyinelemeli döngülerinizi yazmanız, "özyinelemeli" yineleyicilere karşı kontrol etmeniz hasChildren()ve kullanmanız gerekir getChildren().

Yani bu kısa bir genel bakış RecursiveIteratorIterator, nasıl farklıdır IteratorIterator? Temelde aynı türden bir soruyu soruyorsunuz: Bir kedi yavrusu ile ağaç arasındaki fark nedir? Her ikisinin de aynı ansiklopedide (veya yineleyiciler için el kitabında) yer alması, ikisi arasında kafanızın karışması gerektiği anlamına gelmez.

Yineleyici

İşi, IteratorIteratorherhangi bir Traversablenesneyi alıp Iteratorarayüzü tatmin edecek şekilde sarmaktır . Bunun bir kullanımı, yineleyici olmayan nesneye yineleyiciye özgü davranışı uygulayabilmektir.

Pratik bir örnek vermek gerekirse, DatePeriodsınıf Traversablebir Iterator. Bu nedenle, değerleri üzerinden döngü yapabiliriz, foreach()ancak normalde yineleyici ile yaptığımız diğer şeyleri, örneğin filtreleme gibi yapamayız.

GÖREV : Önümüzdeki dört haftanın Pazartesi, Çarşamba ve Cuma günleri arasında döngü yapın.

Evet, bu döngü içinde- foreachüzerinden DatePeriodve kullanarak bir önemsizdir if(); ama bu örneğin amacı bu değil!

$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) { … }

Yukarıdaki kod parçası çalışmayacaktır çünkü arayüz CallbackFilterIteratoruygulayan bir sınıf örneği beklemektedir , ancak bu çalışmayacaktır . Ancak, olduğu için bu gereksinimi kullanarak kolayca karşılayabiliriz .IteratorDatePeriodTraversableIteratorIterator

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

Gördüğünüz gibi, bunun yineleyici sınıflar üzerinde yineleme veya özyineleme ile hiçbir ilgisi yoktur ve burada IteratorIteratorve arasındaki fark yatmaktadır RecursiveIteratorIterator.

Özet

RecursiveIteraratorIteratorbir RecursiveIterator("tekrarlanabilir" yineleyici) üzerinde yineleme yapmak , mevcut özyinelemeli davranışı kullanmak içindir.

IteratorIteratorIteratoryineleyici olmayan Traversablenesnelere davranış uygulamak içindir .


Is not IteratorIteratoriçin doğrusal sıra kastetmek standart tip sadece Traversablenesnelere? Olduğu foreachgibi onsuz kullanılabilenler ? Ve daha da ötesi, bir RecursiveIterator her zaman a Traversabledeğil ve bu nedenle sadece IteratorIteratordeğil, aynı zamanda RecursiveIteratorIteratorher zaman " Iteratoryineleyici olmayan, Gezilebilir nesnelere davranış uygulamak için" mi? (Şimdi foreachyineleyici türü arabirim uygulayan konteyner nesnelerine yineleyici nesnesi aracılığıyla yineleme türünü uyguladığını söyleyebilirim , bu nedenle bunlar her zaman yineleyici kapsayıcı nesnelerdir Traversable)
hakre

Cevabımın belirttiği gibi, IteratorIteratortamamen Traversablenesneleri bir Iterator. Daha fazlası yok . Görünüşe göre bu terimi daha genel olarak uyguluyorsunuz.
06

Görünüşte bilgilendirici bir cevap. Bir soru, RecursiveIteratorIterator aynı zamanda nesneleri Yineleyici davranışına erişebilecekleri şekilde sarmaz mıydı? İkisi arasındaki tek fark, RecursiveIteratorIterator'ın detaya inebilmesi, IteratorIterator'ın ise detaya gidememesidir.
Mike Purcell

@salathe, yinelemeli yineleyicinin (RecursiveDirectoryIterator) hasChildren (), getChildren () davranışını neden uygulamadığını biliyor musunuz?
anru

8
"Tekrarlanabilir" demek için +1. Bu isim uzun bir süre beni yanlış yola saptırıyor çünkü Recursivein RecursiveIterator, davranışı ima ediyor, oysa daha uygun bir isim yeteneği tanımlayan bir isim olurdu RecursibleIterator.
keçi

0

İle kullanıldığında iterator_to_array(), RecursiveIteratorIteratortüm değerleri bulmak için diziyi özyinelemeli olarak gezer. Orijinal diziyi düzleştireceği anlamına gelir.

IteratorIterator orijinal hiyerarşik yapıyı koruyacaktır.

Bu örnek size farkı açıkça gösterecektir:

$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));

Bu tamamen yanıltıcıdır. new IteratorIterator(new ArrayIterator($array))eşdeğerdir new ArrayIterator($array)olduğunu, dış IteratorIteratorhiçbir şey yapmıyor. Dahası, çıktının düzleştirilmesinin hiçbir ilgisi yoktur iterator_to_array- sadece yineleyiciyi bir diziye dönüştürür. Düzleştirme, RecursiveArrayIteratorkendi iç yineleyicisinde gezinme biçiminin bir özelliğidir .
Quolonel Questions

0

RecursiveDirectoryIterator, sadece dosya adını değil, tüm yol adını görüntüler. Gerisi iyi görünüyor. Bunun nedeni, dosya adlarının SplFileInfo tarafından üretilmesidir. Bunlar, bunun yerine temel adı olarak görüntülenmelidir. İstenen çıktı şu şekildedir:

$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";
    }
}

çıktı:

tree
 ├ dirA
 │ ├ dirB
 │ │ └ fileD
 │ ├ fileB
 │ └ fileC
 └ fileA
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.