Vložení prvku do pole
Školení, která pořádám
Řekněme, že máme nějaké asociativní pole, do kterého chceme vložit další prvek. Např. pole s povinnými položkami při registraci, do kterého chceme za určitých okolností přidat další prvky. Pokud chceme prvky přidat na konec, je to jednoduché:
<?php
$povinne = array("login" => "Login", "psc" => "PSČ");
if ($uplna_registrace) {
$povinne["email"] = "E-mail";
}
?>
Horší je to v případě, kdy prvek chceme vložit doprostřed pole. Ideálně by se k tomu hodila funkce array_splice, ta ale nezachovává názvy klíčů. Můžeme použít funkci array_slice, řešení je ale krkolomné:
<?php
if ($uplna_registrace) {
$povinne = array_slice($povinne, 0, 1, true) + array("email" => "E-mail") + array_slice($povinne, 1, null, true);
}
?>
Trik, který se dá v tomto případě použít, spočívá ve vytvoření kompletního pole už při inicializaci a odnastavení nadbytečných prvků, když nejsou potřeba:
<?php
$povinne = array("login" => "Login", "email" => "E-mail", "psc" => "PSČ");
if (!$uplna_registrace) {
unset($povinne["email"]);
}
?>
Diskuse
Andrew:
Dík za príma postřeh, ale trošku to nesouvisí s nadpisem článku. Takže skončím opět u array_slice. Předpoklad definice pole dopředu je opravdu jen pro značně omezenou množinu (například ho nepoužiji při získání dat z db a následném rozšíření struktury).
Peter Listiak:
Nejako tomu nerozumiem. Naco je dobre pridavat prvky niekam "do stredu" asociativneho pola. Nestaci, ked sa to prida nakoniec? Ved stale k tomu pristupujem cez kluc.
Pole můžu chtít následně i procházet, potom je pořadí prvků důležité.
Příkladem použití je třeba pole atributů HTML elementu (http://phpfashion.com/nette-web-html-pomocnik-php-programatora). Vytvořím si objekt představující element a postupně mu dosadím (v libovolném pořadí) jednotlivé atributy do asociativního pole. Renderování pak spočívá ve vypsání jeho názvu a všech atributů s nenulovou (!== NULL) hodnotou, k procházení se použije právě foreach.
Konkrétně u elementu IMG by bylo šikovné, aby atribut SRC byl vždy uveden jako první a dále aby HEIGHT následoval po WIDTH. Což lze řešit buď poměrně krkolomným přesunem klíčů v poli, nebo tak, že už při vytvoření elementu IMG nastavím do pole atributů hodnotu array('src'=>NULL, 'width'=>NULL, 'height'=>NULL)
JimX:
Můžu se zeptati, jestli to pořadí SRC, WIDTH, HEIGHT má nějaký reálný význam, nebo to tak prostě jenom chcete :)
ivan_d:
No nevím, asociativní pole a pořadí mi stále nesedí. Ten popsaný úkol lze splnit prostřednictvím pomocného obyčejného pole s klíči - to určí pořadí:
$order = array('src', 'width', 'height');
foreach($order as $key){
if(!is_null($settings[$key])){
...
}
}
Peter Listiak:
Ale prave pri atributoch HTML elementu mi na poradi nezalezi (ak sa teda nebavime o estetike) a teda toto robit nemusim. Ale uznavam, ze niekedy sa mozu objavit pripady kedy na poradi zalezi.
Jakub Vrána :
Je žádoucí, aby si prohlížeč načetl nejdřív URL obrázku, aby ho hned mohl začít stahovat, a potom rozměry, aby věděl, kolik pro něj má vyhradit místa. Většinou se celá značka přenese najednou, tak na tom nezáleží, ale někdy může být uprostřed značky konec paketu, tak se rozdíl projeví.
Otázkou ale je, jestli prohlížeče značku vůbec zpracovávají předtím, než ji celou načtou.
david@grudl.com:
To sem nemůžeš takhle napsat, vem si kolik lidí teď bude po nocích překopávat své weby :-)
Radek:
Myslím si, že to je milná informace. Mám docela pomalé připojení k netu tak si myslím, že je žádoucí mít nejdřív height a width a až potom adresu obrázku. Prohlížeč si při načítání vyhradí místo pro obrázek a pokračuje dál ve formátování stránky. Pokud nejsou rozměry dány, nikomu nepřeju vidět jak se to celé hýbe podle toho kolik je z obrázku načteno.
Joelp:
Nechci někomu brát iluze, jak funguje prohlížeč, ale například Firefox mi nejdříve stáhne všechny soubory text/html a až následně stahuje obrázky. Takže pozice atributů je absolutně nepodstatná (co se týče rychlosti).
Jakub Vrána :
Mě tedy ne. Firefox 3.0.5 pod Windows v následujícím kódu stáhne dřív obrázek než zbytek HTML:
<img src="jakub.jpg" alt="" />
<?php
ob_flush();
flush();
sleep(10);
?>
A neřekl bych, že je to nějaká anomálie, spíš jsi provedl špatný úsudek.
Značku nicméně zpracuje až po jejím celém načtení, což se dá potvrdit přesunutím sleep() dovnitř značky.
Joelp:
Použil jsem wireshark a ten mi jasně ukázal že se mi (linux) nejdřív stáhne HTML a až následně obrázek.
Jakub Vrána :
Tak si ten kód vyzkoušej. Obrázek je jednoduše vidět ještě před nahráním celé stránky. Bez sleep() je možné i to, že se rychleji stihne dotáhnout HTML než se začne stahovat obrázek, obecně to ale neplatí.
Joelp:
Tak jsem to vyzkoušel a nemůžu potvrdit tvoje tvrzení.
Wireshark mi píše:
AAAA joelp.wz.cz
Standard query response A 88.86.113.136
SYN
SYN, ACK
ACK
GET /test/ HTTP/1.1 (obsahuje komplet HTML)
ACK
HTTP/1.1 200 OK (text/html)
ACK
GET /test/moto_0376.jpg HTTP/1.1
Příklad je zde: http://joelp.wz.cz/test/
Jakub Vrána :
Samotný sleep() nestačí - data se do prohlížeče posílají až když se to vyplatí. V mém příkladu není ob_flush() a flush() pro nic za nic. Vyzkoušej ten příklad ode mě a pak se vrať.
Joelp:
Zdá se, že to velmi závisí na nastavení serveru. Ve výše uvedeném testu se to chová stále stejně i s použitím ob_flush(); a flush();. Když jsem to pak zkoušel na lokálu, tak se to chovalo přesně podle Tebe.
Michal:
Výborný tip, díky za něj. Dřív jsem byl zvyklý hledat řešení svých problémů v diskuzích na php.net (např. na stránkách s funkcemi). Teď chodím první sem :-)
Qwerty:
a co když chci přidat prvek do pole třeba takového a nevím kolik má prvků?
$a = array(2, 3, 4);
Diskuse je zrušena z důvodu spamu.