Bagaimana cara RecursiveIteratorIterator
kerjanya?
Manual PHP tidak banyak didokumentasikan atau dijelaskan. Apa perbedaan antara IteratorIterator
dan RecursiveIteratorIterator
?
Bagaimana cara RecursiveIteratorIterator
kerjanya?
Manual PHP tidak banyak didokumentasikan atau dijelaskan. Apa perbedaan antara IteratorIterator
dan RecursiveIteratorIterator
?
RecursiveIteratorIterator
kerjanya, apakah Anda sudah mengerti cara IteratorIterator
kerjanya? Maksud saya pada dasarnya sama, hanya antarmuka yang dikonsumsi oleh keduanya yang berbeda. Dan apakah Anda lebih tertarik pada beberapa contoh atau Anda ingin melihat perbedaan dari implementasi kode C yang mendasarinya?
IteratorIterator
peta Iterator
dan IteratorAggregate
menjadi Iterator
, di mana REcusiveIteratorIterator
digunakan untuk melintasi recusivly aRecursiveIterator
Jawaban:
RecursiveIteratorIterator
adalah traversal pohonIterator
pelaksana beton . Ini memungkinkan programmer untuk melintasi objek kontainer yang mengimplementasikan antarmuka, lihat Iterator di Wikipedia untuk prinsip umum, jenis, semantik, dan pola iterator.RecursiveIterator
Dalam perbedaan IteratorIterator
yang merupakan Iterator
traversal objek implementasi konkret dalam urutan linier (dan secara default menerima semua jenis Traversable
dalam konstruktornya), RecursiveIteratorIterator
perulangan memungkinkan atas semua node dalam pohon objek yang diurutkan dan konstruktornya mengambil a RecursiveIterator
.
Singkatnya: RecursiveIteratorIterator
memungkinkan Anda untuk melakukan loop di atas pohon, IteratorIterator
memungkinkan Anda untuk melakukan loop di atas daftar. Saya tunjukkan dengan beberapa contoh kode di bawah ini segera.
Secara teknis, ini bekerja dengan mendobrak linieritas dengan melintasi semua turunan node (jika ada). Hal ini dimungkinkan karena menurut definisi semua anak dari sebuah node kembali a RecursiveIterator
. Tingkat atas Iterator
kemudian secara internal menumpuk RecursiveIterator
s yang berbeda berdasarkan kedalamannya dan menyimpan penunjuk ke sub aktif saat ini Iterator
untuk traversal.
Ini memungkinkan untuk mengunjungi semua simpul pohon.
Prinsip dasarnya sama dengan IteratorIterator
: Antarmuka menentukan jenis iterasi dan kelas iterator dasar adalah implementasi dari semantik ini. Bandingkan dengan contoh di bawah ini, untuk perulangan linier dengan foreach
Anda biasanya tidak terlalu memikirkan detail implementasi kecuali Anda perlu mendefinisikan yang baru Iterator
(misalnya ketika beberapa jenis konkret itu sendiri tidak diimplementasikan Traversable
).
Untuk traversal rekursif - kecuali jika Anda tidak menggunakan Traversal
iterasi traversal yang ditentukan sebelumnya yang sudah memiliki iterasi traversal rekursif - Anda biasanya perlu membuat instance RecursiveIteratorIterator
iterasi yang ada atau bahkan menulis iterasi traversal rekursif yang Traversable
Anda miliki untuk memiliki jenis iterasi traversal ini foreach
.
Tip: Anda mungkin tidak menerapkan yang satu atau yang lain milik Anda, jadi ini mungkin sesuatu yang layak dilakukan untuk pengalaman praktis Anda tentang perbedaan yang mereka miliki. Anda menemukan saran DIY di akhir jawaban.
Perbedaan teknis singkatnya:
IteratorIterator
mengambil apapun Traversable
untuk linier traversal, RecursiveIteratorIterator
membutuhkan lebih spesifik RecursiveIterator
untuk melakukan loop di atas pohon.IteratorIterator
mengekspos utamanya Iterator
melalui getInnerIerator()
, RecursiveIteratorIterator
menyediakan sub- Iterator
hanya aktif saat ini melalui metode itu.IteratorIterator
sama sekali tidak menyadari apa pun seperti orang tua atau anak, RecursiveIteratorIterator
tahu bagaimana cara mendapatkan dan melintasi anak juga.IteratorIterator
tidak membutuhkan tumpukan iterator, RecursiveIteratorIterator
memiliki tumpukan seperti itu dan mengetahui sub-iterator yang aktif.IteratorIterator
memiliki urutannya karena linieritas dan tidak ada pilihan, RecursiveIteratorIterator
memiliki pilihan untuk traversal lebih lanjut dan perlu memutuskan per setiap node (diputuskan melalui mode perRecursiveIteratorIterator
).RecursiveIteratorIterator
memiliki lebih banyak metode daripada IteratorIterator
.Untuk meringkas: RecursiveIterator
adalah jenis konkret dari iterasi (perulangan di atas pohon) yang bekerja pada iteratornya sendiri, yaitu RecursiveIterator
. Itu adalah prinsip dasar yang sama seperti dengan IteratorIerator
, tetapi jenis iterasinya berbeda (urutan linier).
Idealnya, Anda juga dapat membuat set sendiri. Satu-satunya hal yang perlu adalah bahwa iterator Anda mengimplementasikan Traversable
yang mungkin dilakukan melalui Iterator
atau IteratorAggregate
. Kemudian Anda bisa menggunakannya dengan foreach
. Misalnya beberapa jenis objek iterasi rekursif traversal terner pohon bersama dengan antarmuka iterasi yang sesuai untuk objek kontainer.
Mari kita ulas dengan beberapa contoh kehidupan nyata yang tidak terlalu abstrak. Antara antarmuka, iterator beton, objek kontainer, dan semantik iterasi, ini mungkin bukan ide yang buruk.
Ambil daftar direktori sebagai contoh. Pertimbangkan Anda telah mendapatkan file dan pohon direktori berikut pada disk:
Sementara iterator dengan urutan linier hanya melintasi folder dan file tingkat atas (daftar direktori tunggal), iterator rekursif juga melintasi subfolder dan mencantumkan semua folder dan file (daftar direktori dengan daftar subdirektorinya):
Non-Recursive Recursive
============= =========
[tree] [tree]
├ dirA ├ dirA
└ fileA │ ├ dirB
│ │ └ fileD
│ ├ fileB
│ └ fileC
└ fileA
Anda dapat dengan mudah membandingkan ini dengan IteratorIterator
yang tidak melakukan rekursi untuk melintasi pohon direktori. Dan RecursiveIteratorIterator
yang dapat melintasi pohon seperti yang ditunjukkan daftar Rekursif.
Pada awalnya contoh yang sangat mendasar dengan DirectoryIterator
yang mengimplementasikan Traversable
yang memungkinkan foreach
untuk mengulanginya :
$path = 'tree';
$dir = new DirectoryIterator($path);
echo "[$path]\n";
foreach ($dir as $file) {
echo " ├ $file\n";
}
Keluaran contoh untuk struktur direktori di atas adalah:
[tree]
├ .
├ ..
├ dirA
├ fileA
Seperti yang Anda lihat, ini belum menggunakan IteratorIterator
atau RecursiveIteratorIterator
. Sebaliknya itu hanya menggunakan foreach
yang beroperasi pada Traversable
antarmuka.
Karena foreach
secara default hanya mengetahui jenis iterasi bernama urutan linier, kita mungkin ingin menentukan jenis iterasi secara eksplisit. Sekilas mungkin tampak terlalu bertele-tele, tetapi untuk tujuan demonstrasi (dan untuk membuat perbedaan dengan RecursiveIteratorIterator
lebih terlihat nanti), mari kita tentukan tipe linier dari iterasi secara eksplisit menentukan IteratorIterator
jenis iterasi untuk daftar direktori:
$files = new IteratorIterator($dir);
echo "[$path]\n";
foreach ($files as $file) {
echo " ├ $file\n";
}
Contoh ini hampir identik dengan yang pertama, perbedaannya $files
adalah sekarang menjadi IteratorIterator
jenis iterasi untuk Traversable
$dir
:
$files = new IteratorIterator($dir);
Seperti biasa tindakan iterasi dilakukan oleh foreach
:
foreach ($files as $file) {
Outputnya persis sama. Jadi apa bedanya? Yang berbeda adalah objek yang digunakan di dalam foreach
. Dalam contoh pertama ini adalah a, DirectoryIterator
dalam contoh kedua itu adalah IteratorIterator
. Ini menunjukkan fleksibilitas yang dimiliki iterator: Anda dapat menggantinya satu sama lain, kode di dalamnya foreach
terus berfungsi seperti yang diharapkan.
Mari mulai mendapatkan seluruh daftar, termasuk subdirektori.
Karena sekarang kita telah menentukan jenis iterasi, mari pertimbangkan untuk mengubahnya ke jenis iterasi lain.
Kami tahu kami perlu melintasi seluruh pohon sekarang, tidak hanya tingkat pertama. Untuk memiliki pekerjaan dengan sederhana foreach
kita membutuhkan berbagai jenis iterator: RecursiveIteratorIterator
. Dan yang satu itu hanya dapat melakukan iterasi pada objek kontainer yang memiliki RecursiveIterator
antarmuka .
Antarmuka adalah kontrak. Setiap kelas yang mengimplementasikannya dapat digunakan bersama dengan RecursiveIteratorIterator
. Contoh dari kelas tersebut adalah the RecursiveDirectoryIterator
, yang merupakan varian rekursif dari DirectoryIterator
.
Mari kita lihat contoh kode pertama sebelum menulis kalimat lain dengan kata-I:
$dir = new RecursiveDirectoryIterator($path);
echo "[$path]\n";
foreach ($dir as $file) {
echo " ├ $file\n";
}
Contoh ketiga ini hampir identik dengan yang pertama, namun menghasilkan beberapa keluaran yang berbeda:
[tree]
├ tree\.
├ tree\..
├ tree\dirA
├ tree\fileA
Oke, tidak jauh berbeda, nama file sekarang berisi nama jalur di depan, tetapi sisanya terlihat serupa juga.
Seperti yang ditunjukkan contoh, bahkan objek direktori sudah mengimplementasikan RecursiveIterator
antarmuka, ini belum cukup untuk foreach
melintasi seluruh pohon direktori. Di sinilah RecursiveIteratorIterator
beraksi. Contoh 4 menunjukkan bagaimana:
$files = new RecursiveIteratorIterator($dir);
echo "[$path]\n";
foreach ($files as $file) {
echo " ├ $file\n";
}
Menggunakan RecursiveIteratorIterator
alih - alih hanya $dir
objek sebelumnya akan membuat foreach
melintasi semua file dan direktori secara rekursif. Ini kemudian mencantumkan semua file, karena jenis iterasi objek telah ditentukan sekarang:
[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
Ini seharusnya sudah menunjukkan perbedaan antara traversal datar dan pohon. The RecursiveIteratorIterator
mampu melintasi setiap struktur seperti pohon sebagai daftar elemen. Karena terdapat lebih banyak informasi (seperti level yang dilakukan iterasi saat ini), dimungkinkan untuk mengakses objek iterator sambil mengulanginya dan misalnya mengindentasi output:
echo "[$path]\n";
foreach ($files as $file) {
$indent = str_repeat(' ', $files->getDepth());
echo $indent, " ├ $file\n";
}
Dan keluaran dari Contoh 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
Tentu ini tidak memenangkan kontes kecantikan, tetapi ini menunjukkan bahwa dengan iterator rekursif ada lebih banyak informasi yang tersedia daripada hanya urutan linier kunci dan nilai . Bahkan foreach
hanya dapat mengekspresikan linieritas semacam ini, mengakses iterator itu sendiri memungkinkan untuk memperoleh lebih banyak informasi.
Mirip dengan meta-informasi, ada juga cara berbeda yang memungkinkan bagaimana melintasi pohon dan karenanya mengurutkan keluaran. Ini adalah mode dariRecursiveIteratorIterator
dan dapat diatur dengan konstruktor.
Contoh selanjutnya akan memberitahu RecursiveDirectoryIterator
untuk menghapus entri titik ( .
dan ..
) karena kita tidak membutuhkannya. Tetapi juga mode rekursi akan diubah untuk mengambil elemen induk (subdirektori) terlebih dahulu ( SELF_FIRST
) sebelum anak-anak (file dan sub-subdirektori di subdirektori):
$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";
}
Output sekarang menunjukkan entri subdirektori terdaftar dengan benar, jika Anda membandingkan dengan output sebelumnya yang tidak ada:
[tree]
├ tree\dirA
├ tree\dirA\dirB
├ tree\dirA\dirB\fileD
├ tree\dirA\fileB
├ tree\dirA\fileC
├ tree\fileA
Karena itu, mode rekursi mengontrol apa dan kapan brach atau leaf di pohon dikembalikan, untuk contoh direktori:
LEAVES_ONLY
(default): Hanya daftar file, tidak ada direktori.SELF_FIRST
(atas): Daftar direktori dan kemudian file-file di sana.CHILD_FIRST
(tanpa contoh): Buat daftar file di subdirektori terlebih dahulu, lalu direktori.Output dari Contoh 5 dengan dua mode lainnya:
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
Jika Anda membandingkannya dengan traversal standar, semua hal ini tidak tersedia. Oleh karena itu, iterasi rekursif sedikit lebih kompleks ketika Anda perlu membungkusnya, namun mudah digunakan karena berperilaku seperti iterator, Anda memasukkannya ke dalam foreach
dan selesai.
Saya pikir ini adalah contoh yang cukup untuk satu jawaban. Anda dapat menemukan kode sumber lengkap serta contoh untuk menampilkan ascii-tree yang bagus di intinya: https://gist.github.com/3599532
Lakukan Sendiri: Buat
RecursiveTreeIterator
Pekerjaan Baris demi Baris.
Contoh 5 menunjukkan bahwa ada meta-informasi tentang status iterator yang tersedia. Namun, ini sengaja ditunjukkan dalam yang foreach
iterasi. Dalam kehidupan nyata, ini secara alami termasuk di dalam RecursiveIterator
.
Contoh yang lebih baik adalah RecursiveTreeIterator
, ini menangani indentasi, awalan, dan sebagainya. Lihat fragmen kode berikut:
$dir = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$lines = new RecursiveTreeIterator($dir);
$unicodeTreePrefix($lines);
echo "[$path]\n", implode("\n", iterator_to_array($lines));
Ini RecursiveTreeIterator
dimaksudkan untuk bekerja baris demi baris, hasilnya cukup lurus ke depan dengan satu masalah kecil:
[tree]
├ tree\dirA
│ ├ tree\dirA\dirB
│ │ └ tree\dirA\dirB\fileD
│ ├ tree\dirA\fileB
│ └ tree\dirA\fileC
└ tree\fileA
Saat digunakan dalam kombinasi dengan a, RecursiveDirectoryIterator
ini akan menampilkan seluruh nama jalur dan bukan hanya nama file. Sisanya terlihat bagus. Ini karena nama file dibuat oleh SplFileInfo
. Itu harus ditampilkan sebagai nama dasar sebagai gantinya. Output yang diinginkan adalah sebagai berikut:
/// Solved ///
[tree]
├ dirA
│ ├ dirB
│ │ └ fileD
│ ├ fileB
│ └ fileC
└ fileA
Buat kelas dekorator yang bisa digunakan dengan RecursiveTreeIterator
sebagai pengganti RecursiveDirectoryIterator
. Ini harus memberikan nama dasar saat ini, SplFileInfo
bukan nama jalur. Fragmen kode terakhir akan terlihat seperti ini:
$lines = new RecursiveTreeIterator(
new DiyRecursiveDecorator($dir)
);
$unicodeTreePrefix($lines);
echo "[$path]\n", implode("\n", iterator_to_array($lines));
Fragmen-fragmen ini termasuk $unicodeTreePrefix
merupakan bagian dari inti dalam Lampiran: Lakukan Sendiri: Buat RecursiveTreeIterator
Pekerjaan Baris demi Baris. .
RecursiveIteratorIterator
karena ini sama dengan jenis lain tetapi saya memberikan beberapa info teknis tentang cara kerjanya sebenarnya. Contoh yang menurut saya menunjukkan perbedaannya dengan baik: jenis iterasi adalah perbedaan utama di antara keduanya. Tidak tahu jika Anda membeli jenis iterasi yang Anda koin itu sedikit berbeda tetapi IMHO tidak mudah dengan jenis iterasi semantik yang dimiliki.
Apa perbedaan dari
IteratorIterator
danRecursiveIteratorIterator
?
Untuk memahami perbedaan antara kedua iterator ini, pertama-tama kita harus memahami sedikit tentang konvensi penamaan yang digunakan dan apa yang kami maksud dengan iterator "rekursif".
PHP memiliki iterator non- "rekursif", seperti ArrayIterator
dan FilesystemIterator
. Ada juga iterator "rekursif" seperti RecursiveArrayIterator
dan RecursiveDirectoryIterator
. Yang terakhir memiliki metode yang memungkinkan mereka untuk dibor, yang pertama tidak.
Ketika instance dari iterator ini di-loop sendiri, bahkan yang rekursif, nilainya hanya datang dari level "top" meskipun melakukan looping pada array atau direktori bersarang dengan sub-direktori.
Iterator rekursif mengimplementasikan perilaku rekursif (via hasChildren()
, getChildren()
) tetapi tidak mengeksploitasinya .
Mungkin lebih baik untuk menganggap iterator rekursif sebagai iterator "rekursif", mereka memiliki kemampuan untuk diiterasi secara rekursif tetapi hanya melakukan iterasi pada sebuah instance dari salah satu kelas ini tidak akan melakukannya. Untuk memanfaatkan perilaku rekursif, teruslah membaca.
Di sinilah RecursiveIteratorIterator
masuk untuk bermain. Ia memiliki pengetahuan tentang bagaimana memanggil iterator yang "berulang" sedemikian rupa untuk menelusuri ke dalam struktur dalam loop normal, datar. Ini menempatkan perilaku rekursif ke dalam tindakan. Ini pada dasarnya melakukan pekerjaan untuk melangkahi setiap nilai dalam iterator, mencari untuk melihat apakah ada "anak-anak" untuk muncul kembali atau tidak, dan masuk dan keluar dari koleksi anak-anak itu. Anda memasukkan contoh RecursiveIteratorIterator
ke depan, dan itu menyelam ke dalam struktur sehingga Anda tidak perlu melakukannya.
Jika RecursiveIteratorIterator
tidak digunakan, Anda harus menulis loop rekursif Anda sendiri untuk mengeksploitasi perilaku rekursif, memeriksa iterator "rekursif" hasChildren()
dan menggunakan getChildren()
.
Nah itulah gambaran singkat tentang RecursiveIteratorIterator
, apa bedanya dengan IteratorIterator
? Nah, pada dasarnya Anda menanyakan pertanyaan yang sama seperti Apa perbedaan antara anak kucing dan pohon? Hanya karena keduanya muncul dalam ensiklopedia yang sama (atau manual, untuk iterator) tidak berarti Anda harus bingung di antara keduanya.
Tugasnya IteratorIterator
adalah mengambil Traversable
objek apa pun , dan membungkusnya sedemikian rupa sehingga memenuhi Iterator
antarmuka. Kegunaannya adalah untuk kemudian dapat menerapkan perilaku khusus iterator pada objek non-iterator.
Untuk memberikan contoh praktis, DatePeriod
kelas tersebut Traversable
bukan Iterator
. Dengan demikian, kita dapat mengulang nilainya dengan foreach()
tetapi tidak dapat melakukan hal-hal lain yang biasanya kita lakukan dengan iterator, seperti pemfilteran.
TUGAS : Ulangi hari Senin, Rabu, dan Jumat dalam empat minggu berikutnya.
Ya, ini sepele dengan- foreach
melewati DatePeriod
dan menggunakan if()
dalam loop; tapi bukan itu inti dari contoh ini!
$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) { … }
Cuplikan di atas tidak akan berfungsi karena CallbackFilterIterator
mengharapkan instance dari kelas yang mengimplementasikan Iterator
antarmuka, DatePeriod
padahal tidak. Namun, karena itu Traversable
kami dapat dengan mudah memenuhi kebutuhan itu dengan menggunakan IteratorIterator
.
$period = new IteratorIterator(new DatePeriod(…));
Seperti yang Anda lihat, ini tidak ada hubungannya sama sekali dengan iterasi kelas iterator atau rekursi, dan di situlah letak perbedaan antara IteratorIterator
dan RecursiveIteratorIterator
.
RecursiveIteraratorIterator
adalah untuk melakukan iterasi RecursiveIterator
(iterator "berulang"), mengeksploitasi perilaku rekursif yang tersedia.
IteratorIterator
adalah untuk menerapkan Iterator
perilaku ke objek non-iterator Traversable
.
IteratorIterator
hanya tipe standar dari traversal tatanan linier untuk Traversable
objek? Apa yang bisa digunakan tanpa itu foreach
apa adanya? Dan lebih jauh lagi, bukankah RecursiveIterator
selalu a Traversable
dan karena itu tidak hanya IteratorIterator
tetapi juga RecursiveIteratorIterator
selalu "untuk menerapkan Iterator
perilaku ke non-iterator, objek Traversable" ? (Sekarang saya akan mengatakan foreach
menerapkan tipe iterasi melalui objek iterator pada objek kontainer yang mengimplementasikan antarmuka tipe iterator jadi ini adalah objek-kontainer-iterator, selalu Traversable
)
IteratorIterator
adalah kelas yang semuanya tentang membungkus Traversable
objek dalam file Iterator
. Tidak lebih . Anda tampaknya menerapkan istilah tersebut secara lebih umum.
Recursive
in RecursiveIterator
menyiratkan perilaku, sedangkan nama yang lebih cocok adalah yang menggambarkan kemampuan, seperti RecursibleIterator
.
Saat digunakan dengan iterator_to_array()
, RecursiveIteratorIterator
akan secara rekursif menjalankan array untuk menemukan semua nilai. Artinya itu akan meratakan array aslinya.
IteratorIterator
akan mempertahankan struktur hierarki asli.
Contoh ini akan menunjukkan dengan jelas perbedaannya:
$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))
setara dengan new ArrayIterator($array)
, yaitu, bagian luar IteratorIterator
tidak melakukan apa pun. Selain itu, perataan output tidak ada hubungannya dengan iterator_to_array
- itu hanya mengubah iterator menjadi array. Perataan adalah sifat dari cara RecursiveArrayIterator
berjalan iterator bagian dalamnya.
RecursiveDirectoryIterator menampilkan seluruh nama jalur dan bukan hanya nama file. Sisanya terlihat bagus. Ini karena nama file dibuat oleh SplFileInfo. Itu harus ditampilkan sebagai nama dasar sebagai gantinya. Output yang diinginkan adalah sebagai berikut:
$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";
}
}
keluaran:
tree
├ dirA
│ ├ dirB
│ │ └ fileD
│ ├ fileB
│ └ fileC
└ fileA