Hiéna szív PHP5

Update: Leírtam az alábbiakban pár baromságot, a lenti hozzászólásban találhatóak a korrektúra és a részletek. A nem igaz részeket dőlt kiemeléssel megjelölöm, félkövérrel pedig az extra infók.

Tegnap felhívott egyik ügyfelem, hogy kb. 4-5 évvel ezelőtt tákolt rendszere php5-re (5.3.3-6) történő frissítés után, üres oldalt ad vissza. Némi konfigurálás után (ugyebár az error riportolás alapban Off a php.ini-ben) az üres oldal tele lett hányva E_Notice-okkal. A notice-ok java része "Undefined offset", "Undefined index" volt tömb műveleteknél.
Némi nézelődés és RTFM után jött a megvilágosodás. PHP fejlesztői igen frappáns, csodakompatibilis megoldást találtak ki:
"Attempting to access an array key which has not been defined is the same as accessing any other undefined variable: an E_NOTICE-level error message will be issued, and the result will be NULL."
Ízlelgessük egy kicsit, legyen bármilyen értéke a tömb elemének, egy figyelmeztetés küldése után az értéke NULL lesz.
Mit is jelent ez? Nézzünk egy példát:


$kutyafule = array("vizsla" => 2, "bobtail" => 2, "snaucer" => 3);
if($kutyafule[0] == 1){
....
}

Ez esetben mindig hamis lesz az eredmény, mert nem numerikusan indexelt a tömb és emiatt "Undefined offset"-et fog dobni. Ugyanez vonatkozik a amikor egy cikluson belül próbálunk numerikus indexxel ugrálni. Ha azt szeretnénk, hogy a tömb numerikusan indexelt legyen akkor létrehozásakor $kutyafule[] = array(); formában kell megadni.

Hogy még nagyobb legyen a katyvasz a tömbbel visszatérő függvények numerikusan indexelt tömbbel térnek vissza.
Pl:


$kutyafule = explode(";", $kutyatar);
if($kutyafule[0] == 1){
....
}

A fenti kód helyesen fog működni, mivel a $kutyatar elemei 0-tól kezdődően végig lesznek indexelve.

A másik vicces dolog az indexek kezelésében beállt változás.
Pl:


if($kutyafule[vizsla]){
....
}

Ha létezik a vizsla elem és nem NULL az értéke, akkor mi fog történni? Semmi, ugyanis a meztelen string E_NOTICE-t emel és automatikusan NULL-ra vágja a vizsla elem értékét. Fasza, nem? Úgy tűnik,"Use of undefined constant" E_NOTICE-t dob, de az érték marad az adott indexhez tartozó.

De ezt még tudják fokozni! Mi van akkor ha egy olyan elemet vizsgálunk ami nincs a tömbben?


if($kutyafule['nincsilyen']){
....
}

Ilyenkor a kód jól fog lefutni, lévén a nem létező tömb elem értéke annó NULL volt, mint ahogy most is az E_NOTICE kiküldése után.
Mielőtt még legyintene az ember, alap PHP beállításban a hibák a http szerver error logjába mennek. Egy rosszul migrált oldal pillanatok alatt teleszórja azt, és utána ember legyen a talpán aki kimagozza a fontos hibákat. Ha kevés az ember tárhelye és nagy az oldal forgalma, akkor a tárhely elfogyása okozhat meglepetést. Az ügyfelemnél, egy másik kód csak 700 MB körüli error logot termelt.
Ez utóbbi azért fontos, mert $_POST[] és $_GET[] masszívan termeli a szemetet.
A helyes megoldás az isset() alkalmazása:


if(isset($_GET['lozung'])){
....
}

Ha létezik az adott elem, akkor az isset() TRUE értéket ad vissza, az összes régi kód meg mehe a kapcsos zárójelek közé.

Szóval, akinek van régi rendszere az ne lepődjön meg ha ilyennel keresik. Aki meg nem akar szívni n+1 évvel korábban írt kódjával az tegye azt amit én: Mondja meg a megrendelőnek, hogy a hibákat javítsa ki a rendszerfrissítést elkövető kolléga.

Stay tooned...

Hozzászólások

Ezek szerint nem csak nálam probléma. A rendszergazda, aki hostolja az oldalt, ragaszkodik a frissítéshez, a megrendelő meg nem akar fizetni ilyenért, mert működnie kellene. Könnyen patthelyzet alakulhat ki, ha nem lehet megértetni velük a probléma forrását. Előjön akár 5.x és 5.3 közötti frissítéssel is, tehát ebbe bárki belefuthat. Az elején tisztázni kell, hogy egy esetleges frissítés bármilyen szoftveren további fejlesztéseket is igényelhet.

--
http://sandor.czettner.hu
http://turaindex.hu

if($kutyafule[vizsla]){
....
}

Helyesen:

$kutyafule["vizsla"]

és nekem nem ütötte le a tömb értékét.

melyik php verzióval próbálkoztál?

Ha azt szeretnénk, hogy a tömb numerikusan indexelt legyen akkor létrehozásakor $kutyafule[] = array(); formában kell megadni

Ez így nem igaz, nem kell a [].

Szerk: ez a kifejezés így eredeti állapotában hozzáad egy üres tömböt a következő indexel. Ha eddig is indexeltük, akkor folytonosan következő, ha csak string elemek vannak, akkor 0-s indexel (utóbbi AFAIK).

És szerintem ez is elírás és nem kell $ az isset() elé, mert különben változó függvény lenne.

if($isset($_GET['lozung'])){

Egyébként a PHP-ben a "tömb", mint olyan nem létezik, az egy hashmap. Annyi extra, hogy képes úgy tenni, mintha egy nullától indexelt tömb lenne.

----------------
Lvl86 Troll

Nem értem a problémádat… PHP-ban alapból numerikusan indexeltek a tömbök, kivéve ha másként van megadva. Ha utóbbi esetről van szó, akkor pedig nem értem miért várod el, hogy a $tomb[0] működjön, pont azt szeretted volna, hogy ne numerikus legyen az index.

"Mondja meg a megrendelőnek, hogy a hibákat javítsa ki a rendszerfrissítést elkövető kolléga."

Tehát a buta/szellemi fogyatékos php "programozó" miatt szívjon a rendszergazda. Teljesen jogos. :P

Egyeztessenek, beszéljék meg, csináljanak migrációs tervet, stb. stb. Legyen teszt, tesztszerver, ha kicsit nagyobb a cucc, akkor projektterv, stb. stb. Na és persze határidők.

Ha ezek nincsenek és a rendszergarázda fogta magát és felgórt egy újabb php-t, akkor a beborított bili kitakarítása a rendszergazda dolga.

Ha meg volt rendesen megtervezett upgrade, dokumentálva és valaki nem tartotta magát hozzá, akkor meg az ő sara.

Pénzes történeteket papírral kell lefedni, nincs mese. Barátság pláne.

Virtualizacio, fastcgi, stb. Oldjak meg, technologia adott.

User szemszogebol: szolgaltatoval szerzodnek x dologra, es ha ezek ki vannak kotve, akkor lehet valtani, ha ettol elter. Altalaban a rugalmasabbik szolgaltato megoldja. Sajat altalanos tapasztalatom az, hogy a rugalmatlanabbtol a rugalmasabb fele mennek az userek.

----------------
Lvl86 Troll

ha a drága programozó kolléga nem gányolna, nem lenne ilyen probléma.
PHP 4 óta van isset(), csak használni is kéne. Jaa, hogy gányoltunk és if ($_GET[kutyafüle]) van if (isset($_SET['kutyafüle'])) helyett?
A programozó kolléga megérdemli a sorsát.
Tessenek megtanulni error_reporting(E_ALL); es display_errors mellett kodolni.

"Attempting to access an array key which has not been defined is the same as accessing any other undefined variable: an E_NOTICE-level error message will be issued, and the result will be NULL."
Ízlelgessük egy kicsit, legyen bármilyen értéke a tömb elemének, egy figyelmeztetés küldése után az értéke NULL lesz.

Teves. Nem lesz NULL az erteke, nem irja felul, mert nincs is mit felulirjon (definialatlan ugye). Kuld egy figyelmeztetest, majd a KIFEJEZES erteke lesz NULL, szoval ha valami hosszabb szamitast vegeznel vele, akkor ott NULLkent fog szerepelni.

"A helyes megoldás az isset() alkalmazása:"
if($isset($_GET['lozung'])){
....
}

Egyreszt ahogy mar irtak, $isset helyett isset siman. Masreszt ezzel adtunk a szarnak egy pofont: $_GET['lozung'] ugyanugy nem letezik, es elobb ertekeli ki, mint az issetet.
A helyes megoldas az array_key_exists() alkalmazasa:
if(array_key_exists('lozung',$_GET))
{
...
}

"Mielőtt még legyintene az ember, alap PHP beállításban a hibák a http szerver error logjába mennek. Egy rosszul migrált oldal pillanatok alatt teleszórja azt, és utána ember legyen a talpán aki kimagozza a fontos hibákat. Ha kevés az ember tárhelye és nagy az oldal forgalma, akkor a tárhely elfogyása okozhat meglepetést. Az ügyfelemnél, egy másik kód csak 700 MB körüli error logot termelt."
A rendszergazdi teszi fel az uj PHP verziot, es a logot is o nezi. Ra tartozik, ez teljesen rendben van igy (de atallithato).
Az persze nincs rendben, ha egy koder direkt arra jatszik, hogy a $t[0] majd NULL lesz ha 0 nem definialt a tombben. Ha azt akarja, hogy NULL legyen, allitsa be! De ez nem a nyelv hibaja.
Amugy a rendszergazdi ha akarja, beallithatja, hogy notice-t ne logoljon csak afelett. Igy a fontos hibakat megtudja, a notice-al meg ugyanazt csinalja, mint a hanyag koder: leszarja.

if($kutyafule[vizsla]){
....
}
"Ha létezik a vizsla elem és nem NULL az értéke, akkor mi fog történni? Semmi, ugyanis a meztelen string E_NOTICE-t emel és automatikusan NULL-ra vágja a vizsla elem értékét. Fasza, nem?"
Helyesen: probalja ertelmezni szerencsetlen a hibas kodot. Mas nyelven kapnal egy "syntax error, sorry" uzenetet (opcionalisan a hiba helyevel megtoldva), itt rajon, hogy az indexbe valoszinuleg stringet akartal irni, ezert atalakitja stringre, de figyelmeztet, hogy biztos igy akartad-e. Ja, es nem lesz a vizsla NULL, mert nincs is beallitva.

Ja, meg valami:
"Ha azt szeretnénk, hogy a tömb numerikusan indexelt legyen akkor létrehozásakor $kutyafule[] = array(); formában kell megadni"
Fent mar irtak, hogy a [] nem kell. Igy azt csinalna, hogy a kutyafule egy tomb lenne, aminek a kovetkezo (itt 0-as indexu) eleme egy ures tomb.
A sima [] ugyanis a kovetkezo numerikus tombelemet jelenti:
$t=array();
$t[]="alma"; //$t[0]="alma";
$t[]="banan"; //$t[1]="banan";
$t[]="citrom"; //$t[2]="citrom";

--
Auto correct can go straight to He'll.

Kipróbáltad? Csak akkor kapsz E_NOTICE-t, ha az értéket akarod megkapni, de értékadásnál nem kapsz. Lásd még: http://php.net/manual/en/language.types.array.php

$arr[key] = value;
$arr[] = value;
// key may be an integer or string
// value may be any value of any type

If $arr doesn't exist yet, it will be created, so this is also an alternative way to create an array. To change a certain value, assign a new value to that element using its key. To remove a key/value pair, call the unset() function on it.[/qoute]

Nah, hazaértem, csináltam egy kis testscriptet.


<?php
print "Inicializálatlan tömb: <br />";
$belabacsi['belaneni']=1;
if($belabacsi[0]){
	print "<br />Inicializálatlan Belaneni szereti numerikus indexelést!<br /><br />";
}else{
	print "<br />Inicializálatlan Belaneni NEM szereti numerikus indexelést!<br /><br />";
}
unset($belabacsi);
print "Inicializált tömb, értékmegadás nélkül:<br />";
$belabacsi=array();
$belabacsi['belaneni']=1;
if($belabacsi[0]){
	print "<br />Inicializált Belaneni szereti numerikus indexelést!<br /><br />";
}else{
	print "<br />Inicializált Belaneni NEM szereti numerikus indexelést!<br /><br />";
}
unset($belabacsi);
print "Inicializált tömb, értékmegadás nélkül, numerikus indexeléssel:<br />";
$belabacsi[]=array();
$belabacsi['belaneni']=1;
if($belabacsi[0]){
	print "<br />Inicializált Belaneni szereti numerikus indexelést!<br /><br />";
}else{
	print "<br />Inicializált Belaneni NEM szereti numerikus indexelést!<br /><br />";
}
print "Inicializálatlan tömb lekérdezése numerikus tartalommal rendelkező változóval:<br />";
unset($belabacsi);
$belabacsi['belaneni']=1;
$i=0;
if($belabacsi[$i]){
	print "<br />Inicializálatlan Belaneni szereti numerikus indexelést!<br /><br />";
}else{
	print "<br />Inicializálatlan Belaneni NEM szereti numerikus indexelést!<br /><br />";
}
unset($belabacsi);
print"Inicializált tömb, értékmegadás nélkül lekérdezése numerikus tartalommal rendelkező változóval:<br />";
$belabacsi=array();
$belabacsi['belaneni']=1;
$i=0;
if($belabacsi[$i]){
	print "<br />Inicializált Belaneni szereti numerikus indexelést változóval!<br /><br />";
}else{
	print "<br />Inicializált Belaneni NEM szereti numerikus indexelést változóval!<br /><br />";
}
unset($belabacsi);
print "Inicializált tömb, értékmegadás nélkül, numerikus indexeléssel, lekérdezése numerikus tartalommal rendelkező változóval:<br />";
$belabacsi[]=array();
$belabacsi['belaneni']=1;
$i=0;
if($belabacsi[$i]){
	print "<br />Inicializált Belaneni szereti numerikus indexelést változóval!<br /><br />";
}else{
	print "<br />Inicializált Belaneni NEM szereti numerikus indexelést változóval!<br /><br />";
}
print "Nem létező elem névvel történő meztelen lekérdezése és vizsgálata:<br />";
if($_GET[belaneni]){
	print "<br />Nem létező meztelen Belaneni szereti névvel történő indexelést!<br /><br />";
}else{
	print "<br />Nem létező meztelen Belaneni NEM szereti névvel történő indexelést!<br /><br />";
}

print "Nem létező elem névvel történő lekérdezése és vizsgálata:<br />";
if($_GET['belaneni']){
	print "<br />Nem létező Belaneni szereti névvel történő indexelést!<br /><br />";
}else{
	print "<br />Nem létező Belaneni NEM szereti névvel történő indexelést!<br /><br />";
}

print "Létező elem névvel történő meztelen lekérdezése és vizsgálata:<br />";
if($_GET[belabacsi]){
	print "<br />Meztelen Belabacsi szereti névvel történő indexelést!<br /><br />";
}else{
	print "<br />Meztelen Belabacsi NEM szereti névvel történő indexelést!<br /><br />";
}

print "Létező elem névvel történő lekérdezése és vizsgálata:<br />";
if($_GET['belabacsi']){
	print "<br />Belabacsi szereti névvel történő indexelést!<br /><br />";
}else{
	print "<br />Belabacsi NEM szereti névvel történő indexelést!<br /><br />";
}
?>

A futásának az eredménye http://localhost/phptest.php?belabacsi=1-el meghívva:


Inicializálatlan tömb:
Notice: Undefined offset: 0 in /var/www/phptest.php on line 4
Inicializálatlan Belaneni NEM szereti numerikus indexelést!

Inicializált tömb, értékmegadás nélkül:
Notice: Undefined offset: 0 in /var/www/phptest.php on line 13
Inicializált Belaneni NEM szereti numerikus indexelést!

Inicializált tömb, értékmegadás nélkül, numerikus indexeléssel:

Inicializált Belaneni NEM szereti numerikus indexelést!

Inicializálatlan tömb lekérdezése numerikus tartalommal rendelkező változóval:
Notice: Undefined offset: 0 in /var/www/phptest.php on line 31
Inicializálatlan Belaneni NEM szereti numerikus indexelést!

Inicializált tömb, értékmegadás nélkül lekérdezése numerikus tartalommal rendelkező változóval:
Notice: Undefined offset: 0 in /var/www/phptest.php on line 41
Inicializált Belaneni NEM szereti numerikus indexelést változóval!

Inicializált tömb, értékmegadás nélkül, numerikus indexeléssel, lekérdezése numerikus tartalommal rendelkező változóval:

Inicializált Belaneni NEM szereti numerikus indexelést változóval!

Nem létező elem névvel történő meztelen lekérdezése és vizsgálata:
Notice: Use of undefined constant belaneni - assumed 'belaneni' in /var/www/phptest.php on line 57 Notice: Undefined index: belaneni in /var/www/phptest.php on line 57
Nem létező meztelen Belaneni NEM szereti névvel történő indexelést!

Nem létező elem névvel történő lekérdezése és vizsgálata:
Notice: Undefined index: belaneni in /var/www/phptest.php on line 64
Nem létező Belaneni NEM szereti névvel történő indexelést!

Létező elem névvel történő meztelen lekérdezése és vizsgálata:
Notice: Use of undefined constant belabacsi - assumed 'belabacsi' in /var/www/phptest.php on line 71
Meztelen Belabacsi szereti névvel történő indexelést!

Létező elem névvel történő lekérdezése és vizsgálata:

Belabacsi szereti névvel történő indexelést!

Mint látható tévedtem az indexelt tömb numerikus megcímzésével és a "meztelen string" kezelésével kapcsolatosan. Előbbire ronda workaroundként használható az array_keys:


$kutyafule = array("vizsla" => 2, "bobtail" => 2, "snaucer" => 3);
$i = 2;
$kutyatar = array_keys($kutyafule);
print $kutyafule[$kutyatar[$i]];
print $kutyafule[$kutyatar[0]];

--
"Maradt még 2 kB-om. Teszek bele egy TCP-IP stacket és egy bootlogót. "

Nekem az nem vilagos miert nem fer el ketto vagy tobb php egymas mellett...

Az a problémád, hogy próbálják kicsit "strictebbé" tenni a nyelvet? Ennyi sok szar kódot rég láttam egyszerre, mint amit te itt felvonultattál.

Látod, inkább füvet szívnál, röhögve leszarnád az egészet. :)
--
Fight / For The Freedom / Fighting With Steel

Jeleznem, hogy a nem letezo tombelemre null-lal valo visszateres az olyan scriptnyelveknel altalanos jelenseg, ahol nincsenek kimondottan exceptionok. Ha ki akarok valamit venni egy tombbol, akkor alapszinten illik leellenorizni, hogy az ott van es ugy van ott, ahogy kell. Ezt akkor lehet csak megkerulni, ha egeszen biztos, hogy az lesz benne, ami, mert peldaul 5 sorral feljebb magunk pakoltuk bele. En meg neha az SQL lekerdezesnek is utanamegyek, ha nem tudok megbizni benne, peldaul ha a config SQL-bol jon. Egyebkent a PHP-ban is, meg a tobbi nyelvben is egyszeruen hasznalhato kulcsellenorzesek vannak a tombokre, sot a PHP-nal meg ott az isset() is.
--

Ki oda vagyik, hol szall a galamb, elszalasztja a kincset itt alant. | Gentoo Portal