ugrás a tartalomhoz

Haladó PHP: kb. '1' == '2' ...parser bug?

prom3theus · 2011. Júl. 2. (Szo), 23.16

<?php
$s1 = '00050003000500000008000100000000';
$s2 = '00050003000500000008000200000000';
var_dump((string)$s1 == (string)$s2? 'y' : 'n');
?>
A var_dump() kimenete: y

Ez Ubuntu Linux alatt, 5.3.5-ös PHP-val fordult elő (semmi extra modul, hacsak az xdebug annak nem számít). Érdeklődve kérdezem: elmagyarázná valaki, hogyan lehetséges ez?

Megjegyzés: ez a kimenet felvet bizonyos kérdéseket azért az MD5 hash-ek összehasonlításakor is...

A konkrét feladatban egyébként arra lenne szükségem, hogy a két stringből melyik a "kisebb" és melyik a "nagyobb", vagy persze adott esetben egyenlőek-e. Verziószámokat szeretnék ellenőrizni úgy, hogy a fentihez hasonló normál alakra hozom őket, elkerülve azt, hogy külön erre a problémára egy osztályt kelljen írnom és implementálni kelljen minden komparáló operátorra egy metódust.

Előre is köszi a segítséget!
 
1

strcmp

janoszen · 2011. Júl. 2. (Szo), 23.32
Az strcmp mit mond?
2

számok vs string

Poetro · 2011. Júl. 2. (Szo), 23.57
Az == operátor valószínűleg előbb számmá alakítja a stringet, ami így egyenlőnek fog tűnni. Használj helyette ===-t
3

Így van, mivel ezek numerikus

bh · 2011. Júl. 3. (V), 01.06
Így van, mivel ezek numerikus adatot tartalmazó karakterláncok. Ezt a PHP felismeri számmá alakítja (igazából floatá, de ez függ attól, hogy hány bites rendszeren vagy). Tehát az ==-vel olyan mintha ezt írnád ebben az esetben: (float)$1 == (float)$2

Update: Itt a végén hülyeséget írhattam, ez inkább (int)$1 == (int)$2 lesz, és mivel túlléped az int max értékét, azért lesz egyenlő (ilyenkor megkapja mind2 változód a max int értéket). Azért is gondolom így, mert float esetében elég furcsa lenne, ha egyenlőségre jutna a kiértékelés (megzavart kicsit a dolog, mert fura hogyha átlépi a max int értéket a változó, akkor nem kasztolódik floatra)
5

Nem írtál

H.Z. v2 · 2011. Júl. 3. (V), 07.37
Nem írtál hülyeséget.
Lásd:
php > $n="100000000000000000001000000000000001000000000000";
php > print $n+0;
1.0E+47

Csakhát a float sem végtelen pontosságú, így floatra konvertálva is kaphatsz azonos értéket.
Bővebben itt: float
4

mas is

Tyrael · 2011. Júl. 3. (V), 01.35
mas is felvetette:
http://www.mail-archive.com/internals##kukac##lists.php.net/msg50082.html

szerintem egy bugot lehetne nyitni neki, nem latom, hogy azonos string tipusu valtozok osszehasonlitasanal miert tortenik type jugling.

Tyrael
6

Hogy a működése hülyeség,

H.Z. v2 · 2011. Júl. 3. (V), 07.51
Hogy a működése hülyeség, abban egyetértünk, de ezt nem nevezném bugnak:
Comparison Operators
Example Name Result
$a == $b Equal TRUE if $a is equal to $b after type juggling.


Az == operátor így működik.
Bővebben: operators

A doksi is azt javasolja, amit Poetro írt: === a == helyett (csak valamivel határozottabban :-) )

ui: a linked egy 404-es hibára visz. (bár gyanús a ##kukac## :-) )
8

a link nalam mukodik. igazad

Tyrael · 2011. Júl. 3. (V), 12.06
a link nalam mukodik.

igazad van, dokumentalt viselkedes:
If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically.


string, resource or number string, resource or number Translate strings and resources to numbers, usual math


illetve lasd peldak.

Tyrael
9

Nálam le van tiltva a JS. Azt

H.Z. v2 · 2011. Júl. 3. (V), 12.54
Nálam le van tiltva a JS. Azt hiszem, ezért kapok vissza rossz URL-t.
10

ettol fuggetlenul szerintem

Tyrael · 2011. Júl. 3. (V), 14.40
ettol fuggetlenul szerintem az gaz, hogy a lusta programozok a php megprobalja a szam kinezetu stringeket szamma alakitani az egyenlosegvizsgalatnal, majd csendben adatvesztes tortenik, ami utan a ket eredetileg eltero erteku de azonos tipusu string azonos lesz.

tovabbi problemas esetek:
"-0" == "+0" // true
"0" == "0x00" // true

amugy levlistan volt mar korabban szo, hogy az ilyen implicit type castolasbol eredo adatveszteseknel dobhatna a php egy E_TYPE tipusu hibat.

lehet, hogy felelesztem a temat.

Tyrael
7

A PHP kezdőbarát nyelv

tgr · 2011. Júl. 3. (V), 12.02
Valahol érthető ez a hozzáállás egy olyan nyelvben, aminek a fő feature-je a lapos tanulási görbe:

// GET index.php?a=2&b=10
echo ($_GET['a'] > $_GET['b']) ? 'a > b' : 'a <= b';
azért meglepődnénk, ha ez 'a > b'-t adna, márpedig type juggling nélkül ez a helyzet. Persze működhetne a == máshogy, mint az összes többi relációs operátor, de az se túl intuitív.
11

Köszi a válaszokat, ilyen

prom3theus · 2011. Júl. 3. (V), 17.43
Köszi a válaszokat, ilyen sokra nem is számítottam. Azt sejtettem, hogy itt valami típus alapú feketemágia van a háttérben, ezért is kényszerítettem string típusúvá mindkét argumentumot. A jelek szerint viszont francot se érek ezzel, mert a PHP értelmező szerint ez dafke csakazértis int (vagy float - mindegy...) :'(

Akkor strcmp()-t fogok használni, a kisebb és nagyobb összehasonlításhoz úgyis megfelel. Float-ra egyébként pont a pontatlanság miatt nem akartam konvertálni, szívesen konvertálnám át én ezt int-re persze, de ekkora drabál int-et a PHP nem kezel. Marad az strcmp() tehát és köszi a tippet.

Az egyébként kicsit nonszensz azért, hogy hiába határozom meg a típusát a két stringnek, csak mert a parser má' pedig jobban tudja...

Köszi mégegyszer!
12

A === használatát már

H.Z. v2 · 2011. Júl. 3. (V), 17.51
A === használatát már javasolta Poetro, de a php.net-en lévő doksiban is ezt ajánlották... (talán gyorsabb, mint a strcmp)
Esetleg megoldás lehet ez is, ha ragaszkodsz a == használatához:
"X$valt1"=="X$valt2"
13

utolsó megoldás azért már

Tyrael · 2011. Júl. 3. (V), 20.08
utolsó megoldás azért már kicsit bash feeling. :D

Tyrael
14

Nem kicsit. :D Tudnád, hogy

H.Z. v2 · 2011. Júl. 3. (V), 20.14
Nem kicsit. :D
Tudnád, hogy meglepődtem, amikor kipróbáltam és működött! ;-)
15

Ez az X-es ötlet nagyon állat

prom3theus · 2011. Júl. 4. (H), 13.50
Ez az X-es ötlet nagyon állat :) ezt fogom használni, mégpedig úgy, hogy a függvényem maga fogja a visszatérés elejéhez konkatanálni a karktert. Nekem igazából ez egy logikai rejtvény volt alapvetően: nem szeretném tudni, hogy mi a visszatérés, én csak verziószámokat szerettem volna egymással összehasonlíthatóvá tenni úgy, hogy azonos formára hozom őket és például egy fgv(verz1) < fgv(verz2) ellenőrzéssel meg tudjam állapítani, hogy egyik kisebb-e mint a másik (vagy ritkább esetben pont egyenlő). Mivel a beépített összehasonlító operátorok használata a legegyszerűbb és legátláthatóbb is, elsősorban inkább ezeknek kedvezek. A jelenlegi esetben az === operátort (amit máshol előszeretettel használok) azért szeretném kerülni, mert két azonos típus esetén értelmetlennek tartom (logikailag zavarónak is).

Egyébként: PHP-ben 4 óta létezik strict-egyenlő, vajon miért nem létezik strict-kisebb és strict-nagyobb is?

Köszi mégegyszer az ötletet, frenetikus :)
16

Eszerint linux/unix shell

H.Z. v2 · 2011. Júl. 4. (H), 13.57
Eszerint linux/unix shell programozásban nem vagy otthon? ;-)
(merthogy az ötlet onnan jött, ahogy Tyrael is említette)

Az ===-vel kapcsolatos problémáidat nem teljesen értem, de PHP-ben (is) erősen kezdő szinten állok.
19

Nem, *ix shell script-eket

prom3theus · 2011. Júl. 5. (K), 04.17
Nem, *ix shell script-eket nem sokszor babráltam eddig, sőt a PHP előtt más scriptnyelveket se. Olyat, ami binárisra fordul viszont elég sokat, kivéve a C-t :D (pacal, delphi, basic, vb, asm, MS batch - tetszőleges sorrendben), meg aztán pár éve volt egy elhajlásom Java és JSP irányba, nem sok sikerrel :)
17

Egyébként: PHP-ben 4 óta

tgr · 2011. Júl. 4. (H), 22.14
Egyébként: PHP-ben 4 óta létezik strict-egyenlő, vajon miért nem létezik strict-kisebb és strict-nagyobb is?


Mert azt mondani van értelme, hogy ha a és b különböző típusúak, akkor nem egyenlőek, de annak, hogy ha különböző típusúak, akkor b a nagyobb, nem igazán...
18

Logikus, ugyanakkor szerintem

prom3theus · 2011. Júl. 5. (K), 04.14
Logikus, ugyanakkor szerintem mégis lenne értelme annak, hogy ha A és B nem azonos típusúak, akkor nem lehetséges megállapítani, melyik a kisebb, ezért kivétel keletkezik mindenképp :) vagy egyéb hibajelzés. A lényeg csak azon lenne, hogy az adott operátorral egy pillanatra típusosabbá lehetne tenni az értelmezőt, és nem lenne szükség extra típusellenőrzésre a kódban. Bizonyos hibák is hamarabb kiszűrhetőek lennének így szerintem.

=== esetén is az első vizsgálat az argumentumok típusa, és csak azt követi az értékek azonossága. Ugyanez miért lenne értelmetlen ebben a sorrendben bármelyik másik komparáló operátor esetében?