Autor Zpráva
j0hny666
Profil *
Zdravím,

zajímal by mě názor zkušenějších PHPčkářů na to, jestli je nutné ověřovat, zda byl proměnná (nebo prvek pole) deklarována. Setkal jsem se totiž s několika případy a příklady kdy autor toto pomíjel.

Příklad:

u uživatele mám výpis zpráv - přijaté a odeslané. Zda se zobrazí inbox nebo outbox závisí na nastavení proměnné $_GET v url. Když ale na stránku přistupuji poprvé, url proměnnou neobsahuje. Jednoduše to ošetřím takhle:

if($_GET['messbox'] == "in") $box = "inbox"; else $box = "outbox";

Toto nastaví proměnnou outbox i v případě že $_GET není deklarována. Vyhodí to však výše zmíněný notice.
Je nutné dělat toto:

if(isset($_GET['messbox']))
{
...
}
else $box = "out";

nebo to nemá ve výsledku žádný efekt???

(s tímto případem se setkávám často a rád bych měl úplné znalosti)

Děkuji za odpovědi (a omlouvám se zatak trochu zbytečnou otázku)
Joker
Profil
j0hny666:
zajímal by mě názor zkušenějších PHPčkářů na to, jestli je nutné ověřovat, zda byl proměnná (nebo prvek pole) deklarována.
V době register_globals z toho mohl být docela velký problém, dnes už asi tolik ne.
Ale pořád to je „formálně špatně“ a generuje to notice, takže minimálně je efekt těch kontrol v tom, že to pak nezapleveluje chybový log (nebo v horším případě když to dáte na server, který má nastavené vypisování chyb do stránky, vypisovalo by to jinak hlášky a v horším případě i rozhodilo vzhled stránky).

if($_GET['messbox'] == "in") $box = "inbox"; else $box = "outbox";
No zrovna v takovém případě (a tohle pravda bývá typický případ) to rozšíření je docela nepatrné:
if(!empty($_GET['messbox']) && ($_GET['messbox'] == "in")) $box = "inbox"; else $box = "outbox";
Nebo ještě kratší:
$box = (!empty($_GET['messbox']) && ($_GET['messbox'] == "in")) ? "inbox" : "outbox";

Můj názor je, že ve velké části případů se ta kontrola dělá stejně (protože potřebuji odfiltrovat i prázdnou či nějaké neplatné hodnoty) a v tom zbytku to sice má přínos spíš malý, ale zároveň minimální pracnost, takže já bych ty kontroly dával všude.
ShiraNai7
Profil
Je dobrá praktika psát kód, který negeneruje žádné chyby. (edit: - ale nutnost to není - bohužel)
Pro ošetření proměnných z $_POST, $_GET a podobně si můžeš napsat pomocnou funkci, aby to bylo jednodušší.

function _get($name, $default = null, $array = false)
{
    if(isset($_GET[$name]) && $array === is_array($_GET[$name])) {
        return $_GET[$name];
    }
    return $default;
}

Pak stačí použít:

$box = (('in' === _get('messbox')) ? 'inbox' : 'outbox');

Tato funkce ošetřuje i případ, že na daném indexu v $_GET může být pole, když očekáváš řetězec.
Str4wberry
Profil
Reakce na j0hnyho666:
Pokud nepotřebujete vypisovat „Notice“*, nemá daná isset podmínka vůbec žádný smysl, jediný její výsledek je zesložitění a znepřehlednění kódu.

*) Nebo pokud vás jejich zbytečné vypisování při vývoji nebude otravovat.



Reakce na ShiraNaiho7:
Je to poznámka, ne chyba. Mimochodem, uvedená funkce je celkem samoúčelná. Zavádí nestandardní zápis jen proto, aby umlčela výpis neškodných poznámek.
ShiraNai7
Profil
Str4wberry:
Je to poznámka, ne chyba.

Ano. Ale není dobrá praktika je potlačovat anebo ignorovat. To je samozřejmě otázkou názoru a o tom se tu hádat nechci. V moderních aplikacích se stejně vše převádí na ErrorException.

Zavádí nestandardní zápis jen proto, aby umlčela výpis neškodných poznámek.

Nic neumlčí. Zabrání jim.
j0hny666
Profil *
Díky všem za odpovědi,

koukám že je to asi věc názoru - méně přehledný kód vs. nepřehledný log apod - a že to na funkci scriptu vliv nemá.

Asi budu toto ošetřovat tam kde stačí jeden dva řádky a tam kde je takovýchto více (třeba formulářová pole s předepsanými values) se tím zabývat nebudu... (myslím si že drtivá většina serverů má dnes NOTICE vypnuto.

ShiraNai7

zajímavá funkce, to mě nenapadlo. Díky za tip, vyzkouším ;-)

Děkuji všem
ShiraNai7
Profil
j0hny666:
myslím si že drtivá většina serverů má dnes NOTICE vypnuto.

V procedurální aplikaci co nepřevádí "nativní chyby" na výjimky by mělo být na živém webu vypisování chyb vždy vypnuto.
Ovlivnit to můžeš třeba funkcí error_reporting() anebo ini_set(). Existují direktivy jako display_errors.
Jan Tvrdík
Profil
Str4wberry:
Mimochodem, uvedená funkce je celkem samoúčelná.
Není tomu tak, Str4wberry. Chrání (ač ne příliš elegantně) před (dle mého názoru) nejčastější chybou současných webů a to je chybějící validace, zda je vstupní parametr skalární. (To, že tuto chybu najdeme i tady na diskusi asi nikoho nepřekvapí.)

Elegantnější varianta té samé funkce může vypadat třeba takto:
function _get($name, $default = null, $isArray = false)
{
    if (isset($_GET[$name]) && is_array($_GET[$name]) === $isArray) {
        return $_GET[$name];
    }
    return $default;
}

výpis neškodných poznámek
Je velmi troufalé považovat chyby úrovně E_NOTICE za neškodné.

j0hny666:
Chyby typu E_NOTICE výrazně nedoporučuji ignorovat. Můžeš tak snadno přehlédnout velmi závažné chyby. (Alternativně můžeš použít statickou analýzu, která je schopná skrytým chybám předcházet.)
ShiraNai7
Profil
Jan Tvrdík:
Elegantnější varianta té samé funkce může vypadat třeba takto
Nevím, proč jsem tu podmínku napsal tak zbytečně složitě. Díky za zlepšení, přepsal jsem i svůj příspěvek.
Str4wberry
Profil
Reakce na Jana Tvrdíka:
Je velmi troufalé považovat chyby úrovně E_NOTICE za neškodné.

Domníváš se, že vyvolaná E_NOTICE u kódu
if($_GET['messbox'] == "in") $box = "inbox"; else $box = "outbox";
bude něčemu škodit?

Jaký má smysl do dané podmínky přidat ověření existence daného klíče?
Joker
Profil
j0hny666:
myslím si že drtivá většina serverů má dnes NOTICE vypnuto.
Minimálně vývojový server má mít notice zapnuté a obvykle má i vypisování do stránky (alespoň já bývám líný pořád chodit do logu :-) ), takže to pak je otravné.

[#10] Str4wberry:
Mám za to, že Jan Tvrdík mluví o „řešení“ problému vypnutím notice, ne o tom, že by to v tom jednom konkrétním případě mohlo uškodit.

Ale koukám, že můj původní názor, že dnes už to moc nevadí, ten problém podcenil.
Takže:

Domníváš se, že vyvolaná E_NOTICE u kódu
if($_GET['messbox'] == "in") $box = "inbox"; else $box = "outbox";if($_GET['messbox'] == "in") $box = "inbox"; else $box = "outbox";
bude něčemu škodit?
Na základě diskuse výše zjevně ano: Bude to pořád (minimálně na vývojovém serveru) zobrazovat notice, což nezanedbatelné množství lidí „vyřeší“ tím, že hlášení úrovně notice potlačí, „aby je to pořád neotravovalo“.
A právě to je velmi škodlivý následek.
nevimco2
Profil
Chápu dobře otázku? "Mám varování o tom, že můj kód takto vypadat nemá, že můj neošetřený problém chytá se skřípěním zubů PHPčko, a já se roznodnu radši vypnout hlášení než porblém vyřešit. Je to dobře?"

I jako vtip by to bylo nepovedený.
johnyz
Profil
ačkoliv je to jen NOTICE, měli byste tomu věnovat pozornost a nebrat to na lehkou váhu i když to ničemu nevadí co se týče funkčnosti.

ještě jedna rada, která inteligentním usnadní život, těm druhým to bude jedno a budou to používat po staru.

jednoduché podmínky nezapisujte takto:
if($_GET['messbox'] == "in") $box = "inbox"; else $box = "outbox";

ale
$box = ($_GET['messbox'] == "in") ? "inbox" : "outbox";
Ascaria
Profil
Někde jsem četl, je to už dávno, že notice jsou nejdůležitější chyby vůbec a ignorovat je, je největší chyba co se dá v PHP udělat. Navíc notice se musí přenastavit, aby zastavovalo provádění skriptu, jako to dělá třeba fatal error, pouhé vypsání do stránky nestačí. Obzvlášť to člověk ocení tam, kde je po nějakém příkazu redirect, protože jinak si vůbec nevšimne, že nějaká chyba existuje.. A zákazníkovi to potom vyplivne blbosti, ten si postěžuje šéfovi a komu to pak strhnou z platu?
jenikkozak
Profil
Ascaria:
A zákazníkovi to potom vyplivne blbosti, ten si postěžuje šéfovi a komu to pak strhnou z platu?
Tomu, kdo nedokáže vypnout vypisování poznámek do stránky?
Tori
Profil
Ascaria:
notice se musí přenastavit, aby zastavovalo provádění skriptu, jako to dělá třeba fatal error, pouhé vypsání do stránky nestačí.
A zákazníkovi to potom vyplivne blbosti, ten si postěžuje šéfovi a komu to pak strhnou z platu?

Tohle jsou dvě různé věci, ne? Na localhostu bych měla odchytat co nejvíc chyb, jakýchkoli, a převedení E_NOTICE na ErrorException je jednou z cest k tomu vedoucích. Ale na ostrém webu se očekává, že tam už žádné zásadní chyby (E_WARNING a vyšší) nejsou, a uživatel by neměl vidět systémové chybové hlášky (můžou rozbít design, zablokovat přesměrování, prozradit souborovou strukturu nebo použitý FW/CMS, ...), ale buď nic nebo při fatálních chybách zobrazit vlastní chybovou stránku.
Again
Profil
jenikkozak:
Podle mě to není řešení vypnout vypisování poznámek do stránky. Změní se konfigurace nebo server a hrozí riziko, že se poznámky zase vrátí a napáchají škodu třeba v designu stránky. V tom případě je už lepší převést E_NOTICE na nějaký typ Exception a při zachycení např: logovat (přece jenom Notice by neměl nijak zásadně ovlivnit funkčnost stránky).
ShiraNai7
Profil
Again:
V tom případě je už lepší převést E_NOTICE na nějaký typ Exception a při zachycení např: logovat

To by se muselo dělat už v error_handleru, protože kdyby se ta výjimka vyhodila, tak má na funkčnost vliv vždy.
Again
Profil
ShiraNai7:
Samozřejmě, avšak při nastavení error_handleru si vyhazuji např: ErrorException a všechno to nakonec zpracuji až v nějaké funkci, kterou si nastavím pomocí exception_handleru ...
ShiraNai7
Profil
Again:
Ano, ale to pak tohle:

přece jenom Notice by neměl nijak zásadně ovlivnit funkčnost stránky

.. není pravda. Když vyhodíš exception a zpracuješ ji v exception handleru, skript se ukončí. A to mi přijde jako "ovlivnění funkčnosti stránky" :)

Viz dokumentace:

Sets the default exception handler if an exception is not caught within a try/catch block. Execution will stop after the exception_handler is called.

To znamená, že aby skript pokračoval, nesmíš vyhodit žádnou výjimku (třeba na základě podmínky, že se jedná o notice) a provádět logování v rámci error handleru.
Again
Profil
ShiraNai7:
Aha, tak to mě nenapadlo - díky :)

Vaše odpověď

Mohlo by se hodit

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

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