Autor Zpráva
Tomáš123
Profil
Ahojte, vytvoril som si jednoduché spojenie s databázou:
<?php
    $connection = mysqli_connect("localhost", "root", "", "data");
    if(mysqli_connect_errno()) {
        printf("Chyba číslo %d \n", mysqli_connect_error());
        exit();
    }
    $query = "SELECT `name`, `users_id` FROM `users`";
    if($result = mysqli_query($connection, $query)) {
        while($row = mysqli_fetch_array($result)) {
            echo $row['name']." ".$row['users_id']."<br>\n";
        }
    }
?>
Všetko funguje, ale nerozumiem tomu cyklu na výpis. Prečo sa to prevádza takto? Viem, že funkcia mysqli_fetch_array() vracia pole výsledkov z jedného riadku. Vlastne je to rovnaké ako pri výpise riadkov zo súboru či súborov z adresára (v manuáli je pre mňa správna cesta výpisu úplne nepochopiteľná). Ak by ste mi vysvetlili, čo je podstatou každého výpisu, veľmi by ste mi pomohli.

Vopred ďakujem veľmi pekne za rady.
Joker
Profil
Tomáš123:
Viem, že funkcia mysqli_fetch_array() vracia pole výsledkov z jedného riadku.

No, a pak se ty hodnoty z pole už jen vypíší, to už je triviální.

Možná je problém spíš v pochopení mechanismu, že mysqli_fetch_array, stejně jako readdir u adresáře, vrací false, když už nejsou žádné další záznamy?

Čili ten cyklus je: Načte se další záznam a dokud není false (což znamená, že už jsme na konci), vypíší se jeho údaje.
juriad
Profil
Tomáš123:
Možná také víš, že uvnitř while máš mít podmínku, ale tady žádnou nevidíš, místo ní je tam přiřazení.
Uvedená konstrukce využívá toho, že každé pole, které má alespoň jeden prvek, je považováno za TRUE. A SELECT nikdy nevrátí 0 sloupců, vždy bude alespoň jeden.

Jistě jsi se setkal s konstrukcí přiřazení do více proměnných:
$a = $b = 1;
Zkusme něco víc - uložit do proměnné $cislo 15 a rovnou ho i vynásobit dvěma:
$dvojnasobek = ($cislo = 15) * 2
Ve skutečnosti tedy operátor přiřazení má návratovou hodnotu - vrací svůj levý argument (jestli levý nebo pravý je v PHP jedno*). Pokud bys = zaměnil za +, bylo to zřejmé.
Samozřejmě, že normálně bys napsal:
$cislo = 15;
$dvojnasobek = $cislo * 2;
ale to jsou dva příkazy. Ve while potřebuješ jediný výraz.

Když to dáme dohromady, dostaneš
while($row = ...) {...}
Někdy se můžeš setkat i se zápisem:
while(($row = ...) !== NULL) {...}
který striktně kontroluje NULL**, a nikoli jakoukoli nepravdivou hodnotu (tedy i prádné pole, FALSE, 0, prázdný řetězec a další).

To se může hodit třeba u funkcí jako strpos:
$retezec = "abcabcabcabc";
$hledat = 'c';
$nahradit = 'x';
while($index = strpos($retezec, $hledat)) {
  $retezec[$index] = $nahradit;
}
echo $retezec;
Tento kód se zdá, že funguje; nahradí postupně všechna c v řetězci za x.
Ale zkus si jím nahradit áčka. Ehm, co se to stalo a jak to spravit?
while(($index = strpos($retezec, $hledat)) !== FALSE) {

* Obecně není, v Javě:
        int i;
        long l;

        l = i = 1; // OK
        i = l = 1; // chyba

** Pozor, návratová hodnota funkce mysql_fetch_array a mysqli_fetch_array se liší. Jednou je to FALSE, podruhé NULL
xROAL
Profil
Ešte by som možno doplnil, že mysqli_fetch_array() si ukladá akýsi ukazateľ (pointer, alebo iterátor? - nepoznám terminológiu), môžeme to chápať ako číslo riadku. Na začiatku je to 1, pri zavolaní vráti teda prvý riadok a tento ukazateľ zvýši. Pri druhom volaní je to teda 2, vráti druhý riadok a znovu zvýši ukazateľ. Takto to pokračuje až kým nevráti prázdny výsledok (podľa dokumentácie hodnotu NULL) a tam cyklus while skončí.
Tomáš123
Profil
xROAL:
a tento ukazateľ zvýši
Mám to brať tak, že istá množina funkcií je predpripravená na použitie v cykloch a zahŕňa akýsi auto_increment?

juriad:
Ďakujem za tak obšírnu odpoveď.
že uvnitř while máš mít podmínku
Dalo by sa do cyklu postaviť podmienka, ktorá by bola ukecanejšou obdobou krátkeho zápisu?

Joker:
To o tých návratových hodnotách som nevedel. Ak sa teda riadim xROALovou vetou: „Takto to pokračuje až kým nevráti prázdny výsledok (podľa dokumentácie hodnotu NULL) a tam cyklus while skončí.“, začína mi byť jasné prečo cyklus končí tam kde treba. Predsa je to ale o niečo iné ako obyčajný výraz. Mám krátku úvahu:
Obyčajná najjednoduchšia forma cyklu by mohla byť niečo ako while($a < $b). Za celkom ľahko pochopiteľnú môžme považovať aj formu while($ukazatel != $celkovy-pocet). Je hore uvedená forma akýsi opak tejto?
juriad
Profil
Tomáš123:
Mám to brať tak, že istá množina funkcií je predpripravená na použitie v cykloch a zahŕňa akýsi auto_increment?
Ano, existují funkce, které když zavoláš se stejnými argumenty dvakrát po sobě, tak vrátí pokaždé jiný výsledek.
Zavolání mysqli_fetch_array způsobí vrácení řádku a přesun na další, nebo vrácení NULL, pokud už neexistuje.
Existuje dokonce rozhraní, které definuje metody, které jednotně mění vnitřní stav objektu, tak aby příště vrátili něco jiného.
Existuje i podobná rodinka funkcí; podívej se na funkci next a zkus si pár příkladů s polem. A také se podívej na další v sekci See Also

Dalo by sa do cyklu postaviť podmienka, ktorá by bola ukecanejšou obdobou krátkeho zápisu?
To není možné. Musíš rozlišovat příkazy a výrazy.
Výraz je něco, co má hodnotu; konstanta, proměnná, volání (ne-void) funkce, sečtení, přiřazení.
Příkaz je výraz zakončený středníkem nebo nějaký jazykový konstrukt (podmínky, cykly, volání void funkce se středníkem.
A while je defiovaný tak, že v místě podmínky chce výraz (něco co má hodnotu) a následně tuto hodnotu bude analyzovat, zda je spíš pravdivá nebo nepravdivá.

To o tých návratových hodnotách som nevedel.
Musíš číst dokumentaci. Jak jinak se dozvíš, že funkce mysqli_fetch_array vrací řádek dotazu jako pole a nevrací třeba slona? A když už, tak že vrací toho afrického a nikoli indického.

Je hore uvedená forma akýsi opak tejto?
Neuvažuj nad formou cyklu. Uvažuj nad tím, že while požaduje jako podmínku libovolný výraz. A ten výraz může dělat cokoli; lze rozlišit tři hlavní případy:
1) výraz nemá žádné vedlejší efekty: vyhodnocení $a < $b nic v programu nezmění; můžeš to provádět kolikrát chceš.
2) vnitřní vedlejší efekt: to je volání nějakých funkcí, které změní vnitřní stav objektu ale nic jiného; sem patří třeba ten mysqli_fetch_array; zavolání se stejnými parametry vrátí něco jiného, ale neovlivní to stav okolí.
3) vnější vedlejší efekt: něco co změní okolí vyhodnocovaného výrazu; teď mě napadá jen to přiřazení do proměnné a define.

Ultraobskurní příklad:
echo abc;
while (define('abc' . defined('abc'), 123)) {
  echo abc;
}

Existují programovací jazyky, kde není možné, aby zavolání funkce nebo vyhodnocení výrazu cokoli změnilo. Není ani možné měnit hodnoty proměnných.
Funkce pro přidání či odebrání prvku ze seznamu nemá jinou možnost než vrátit nový seznam (a ten starý nezměnit).
Tomáš123
Profil
juriad:
Ano, existují funkce, které když zavoláš se stejnými argumenty dvakrát po sobě, tak vrátí pokaždé jiný výsledek.
To mi stačí. Išlo mi o pochopenie. Teraz viem, čo sa vo vnútri deje. Príklad readdir, na ktorý som hore odkázal je vlastne tá bežná forma na cyklický výpis obohatená (alebo skôr ošetrená) striktne definovanou hodnotou, pri ktorej sa má cyklus zastaviť (čo si ostatne písal vyššie). Ako strpos() ktorý vracia pozíciu hľadaného znaku (ak sa nájde na prvej pozícii, funkcia vráti 0, ktorá sa pretypuje, však). Vlastne sme to riešili vtedy na ihrisku.

Musíš číst dokumentaci.
Pardon, zle som to napísal. Nevedel som o posunutí ukazateľa. Dokumentáciu samozrejme prejdem predtým, než sa niečo opýtam.

Čo ten príklad, chceš ma vystrašiť, aby som sa už viac nepýtal? :-)
Joker
Profil
juriad:
** Pozor, návratová hodnota funkce mysql_fetch_array a mysqli_fetch_array se liší. Jednou je to FALSE, podruhé NULL
Což jsem ve svém příspěvku napsal špatně, díky za opravu.

Tomáš123:
Mám krátku úvahu:

Neřekl bych, že to jsou opaky, jen dva různé přístupy.
Můžu položky zpracovávat způsobem „zpracuj další položku tak dlouho, dokud není zpracován určitý počet položek“, nebo způsobem „zpracuj další položku tak dlouho, dokud jsou ještě položky ke zpracování“.

Každá varianta se hodí pro určitý typ situací.
Například balení věcí na dovolenou asi bude tím prvním způsobem: Nejdřív si řeknu, kolik zhruba triček budu potřebovat, a potom jich ze skříně tolik vezmu (plus výjimka pro případ, že jich ve skříni tolik není :) ).
Když bych chtěl vystěhovat skříň, volil bych naopak ten druhý algoritmus: Vyndaval věci tak dlouho, dokud ve skříni nějaké jsou.


Případně co se týká té formy zápisu, while (funkce()), začátečníci mívají trochu problém pochopit, jak vlastně ty podmínky a cykly fungují. Není tam žádná magie, pomocí které by příkaz if, while, atd. kontroloval zadaný výraz, ale prostě jen výraz vyhodnotí, převede na boolean a koukne se, jestli vyšlo true, nebo false.

Čili vnitřek podmínky či podmínka cyklu jsou jen výrazy, jejichž výsledek má být boolean.
Tomáš123
Profil
Joker:
Krásne prirovnanie :-)

Čili vnitřek podmínky či podmínka cyklu jsou jen výrazy, jejichž výsledek má být boolean.
Takže sa všetko vyhodnotí podobne ako v podmienke, ale niektoré funkcie majú zabudovaný automatický posun ukazateľa vďaka čomu vedia vypísať obsah poľa či databázy, však...

Takto vysvetlený by so po naštudovaní dokumentácie pochopil snáď i juriadovUltraobskurní příklad“. :-)

Ďakujem všetkým za črepiny. Už tomu rozumiem.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: