[2010–04–22] Zrušení Collections

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
David Grudl
Nette Core | 8218
+
0
-

Každý rozumný jazyk disponuje vestavěnou podporou kolekcí. Jde zejména o třídy:

  • array – uspořádaný seznam prvků, číslovaný obvykle od nuly
  • hash – neuspořádaný seznam prvků indexovaných pomocí klíčů
  • set – neindexovaná a neuspořádaná množina prvků

Array lze pak použít pro reprezentaci datových struktur queue a stack.

PHP místo jakékoliv z těchto struktur disponuje jakýmsi hybridem array & hash. Což je na jedné straně mocná struktura, na druhé straně potenciální zdroj problémů. Třeba uspořádanost záleží na tom, v jakém pořadí prvky do pole přiřazujete, nikoliv na jejich indexu:

$arr[2] = 'druhy';
$arr[1] = 'prvni';
foreach ($arr as $item) echo $item; // vypise 'druhy', 'prvni'

Nette Framework tento nedostatek řešil zavedením vlastních tříd Nette\Collection, konkrétně ArrayList, Hashtable, Set a abstraktního předka Collection.

PHP počínaje verzí 5.3 na implementaci datových struktur pořádně zapracovalo a Nette\Collection ztrácí význam. Nebo to napíšu jinak: nechci v této nice vytvářet konkurenci. Rozhodl jsem se proto Nette\Collection vyjmout z frameworku a přesunul je pro zájemce do extras.

Jak je to s kompatibilitou?

  • Nette\Collection\ArrayList nahrazuje SplQueue (od verze 5.3)
  • Nette\Collection\HashTable nahrazuje ArrayObject (od verze 5.0)
  • Nette\Collection\Set nahrazuje SplObjectStorage (od verze 5.1)

Nicméně API je pochopitelně zcela rozdílné. Třídám SPL také chybí možnost kontrolovat typ vkládaného prvku (což je docela mrzuté) a možnost učinit strukturu pouze pro čtení.

V rámci samotného frameworku využívaly kolekcí třídy MultiRouter a Config. První jmenovaný získá rozhraní ArrayAccess a IteratorAggregate, takže jeho použití se nijak nezmění. V případě Config si změny zaslouží vlastní popis (doplním).

David Grudl
Nette Core | 8218
+
0
-

Tak v současné revizi už byla hrozba naplněna :-)

Pro zajímavost: PHP SPL Data Structures Benchmark.

David Grudl
Nette Core | 8218
+
0
-

Ještě jednu poznámku – SPL třídy jako například ArrayObject nebo i nové SplQueue nebo mají poměrně bohaté API. Což samozřejmě neimplikuje nic špatného. Zatímco API nové SplQueue vypadá rozumně (chybí mi tu ovšem možnost vložit nový prvek dovnitř pole, nějaké insertAfter), API starší ArrayObject je docela odstrašující příklad. (prasácký rukopis Marcuse Boergera v SplQueue vidět není, bo jej napsal někdo jiný, Etienne Kneuss). Zároveň ArrayObject má pošramecenou i runtime-pověst, stačí se podívat, kolikrát je zmíněn v bug trackeru PHP a jen doufám, že Etienne Kneuss odvedl lepší kus práce.

Bohaté API ovšem komplikuje vytváření potomků tříd. Pokud bychom chtěli vytvořit například potomka, který dovoluje přidávat pouze prvky určitého typu, musíme v SplQueue přepsat metody offsetSet, push a unshift, v případě ArrayObject by šlo asi o pět metod. A s rizikem, že další verze PHP přidají další metody.

Především je tu otázka dědičnosti jako takové – dle mého jedna z nejvíce zneužívaných vlastností OOP. V PHP se často dědí jen kvůli neopakování kódu → protože PHP neumí mixiny nebo vícenásobnou dědičnost. V PHP se taky dědí kvůli magickým vlastnostem, což byl příklad ArrayObject jakožto potomka tříd Nette\Collection nebo DibiRow. Všechno proti logice dědičnosti! Docela mě štvalo, že MultiRouter nebo DibiRow má metody jako natcasesort nebo getFlags.

Jinými slovy, nechci (už více) vytvářet:

  • vrstvy nad SPL třídami kolekcí
  • používat SPL třídy kolekcí jako předky tříd frameworku

Z těchto důvodu je MultiRouter implementován jako kompozice s SplQueue / ArrayList, Config jej bude následovat a celá Nette\Collections šla do kytek.

Honza Marek
Člen | 1664
+
0
-

Kytky nejsou tady?

David Grudl
Nette Core | 8218
+
0
-

Moc se mi to nechce zveřejňovat, prostě Collection založené na ArrayObject není nic, čím bych se chlubil.

PS. LazyArrayList z Ormionu by úpravou na něco, jako je aktuální ArrayList, mělo po objektové stránce taky spíš získat, ne? Nebo jsou tam zádrhele? (kromě nemožnosti přetypování přes (array), protože to odhalí privátní $loaded).

Honza Marek
Člen | 1664
+
0
-

Já s tím přepsáním počítám, ale nechce se mi to dělat hned teď :)