"Karaktersorozatok sebessége" PHP-ben
A PHP kétféle idézőjel használatát támogatja, és ráadásul a heredoc megadási módot is alkalmazhatjuk. Sok hiedelem kering azonban arról, hogy ezek közül egyik vagy másik gyorsabb, hatékonyabb eszköz lenne, és kizárólag azt szabad használnunk programjaink írása során. Cikkemben szeretném ezen hiedelmek egy részét megdönteni, valamint bemutatni, hogy egészen kis eszköztárral is igazolhatóak vagy cáfolhatóak az ilyen jellegű állítások, a PHP belső világának ismerete nélkül. Nézzük mire jutunk saját méréseinkkel, ha nekünk "bizonyíték kell, nem ígéret".Az első két példa ugyanazt jelenti, a második kettőből viszont csak az előbbi fog újsort kiírni a kimenetre, az utóbbi magát a
A háromféle karaktersorozat megadási mód támogatása lehetővé teszi a programozók számára, hogy ne kelljen csúnyán festő megoldásokat választaniuk, ha egy karaktersorozatban a körbezárására használt idézőjelet szeretnék alkalmazni. Egyszerűen csak meg kell változtatni a körbezáró idézőjelet, vagy át kell térni a heredoc jelölésre.
Habár kiváló profiler programok állnak rendelkezésre a PHP programok gyenge pontjainak megtalálására, mégsincs speciális kiterjesztésekre szükségünk ahhoz, hogy egyszerűbb méréseket végezhessünk. Az idézőjelekkel kapcsolatos kijelentésekről magunk is meggyőződhetünk a következő egyszerű programmal:A fenti kód nagyrésze a PHP microtime() függvényének dokumentációs oldaláról származik, tehát máskor is könnyen reprodukálható, ha esetleg nem is emlékeznénk a
Ez jól láthatóan azt jelenti, hogy a mérés alapján héttized százalékkal (azaz 0,7 százalékkal) gyorsabb a dupla idézőjelek feldolgozása PHP 4.3.4-ben, mint a szimpla idézőjeleké. Ilyen kis feladat esetén azonban nem lehet eltekinteni a futtatás körülményeitől. Különböző mérések eltérő eredményhez vezetnek, a program alapján minden reprodukálható. Tehát ezért nem érdemes áttérni egyik jelölésről a másikra. A heredoc típusú megadás viszont már látványosan lassabb. Azt is láthatjuk, hogy PHP 5.0.0-ban nem túl jelentős sebességváltozás észlelhető, de szerencsére jó irányban.
Futtassuk tehát le újra a mérést úgy, hogy most az
Mindjárt más. A PHP-nek eléggé sok időt el kell töltenie ebben az esetben azzal, hogy rájöjjön, hogy mi tulajdonképpen nem változót akartunk beilleszteni, hanem magát a dollár jelet, így pedig a dupla idézőjel közel a heredoc mellé szegődik sebességében. Persze ilyenkor körültekintő programozóként sokkal inkább azt kellene írnunk, hogy
A
Kisebb eltérések minden futtatásnál előfordulhatnak, de az arányokon ez nem változtat. Az eredmények azt mutatják, hogy ebben a teszt esetben a változó helyettesítés jelentősen több időbe telik, mint a karaktersorozat hozzáfűzése. Ez azzal magyarázható, hogy a változó nevet meg kell keresni a karaktersorozatban, mely ráadásul kellően bonyolult is lehet (objektum hivatkozással, tömb elemmel), majd pedig ezt helyettesíteni kell az értékével, és csak ezután folytatódhat a feldolgozás. Ebben az egyszerű tesztben hasonló eredményt kapunk, ha a PHP-nek segítünk a változó nevének megtalálásában, azaz
Azt is érdemes leszögezni a mérés eredményei alapján, hogy a PHP nemcsak hibajavításokkal és új szolgáltatásokkal jelenik meg verzióról verzióra, hanem az alapvető nyelvi konstrukciók is változnak, fejlődnek (sajnos időnként lassulnak is). Ezért egy általunk végzett mérés tanulságainak időtállóságában sem lehetünk biztosak, érdemes iőnként újra visszatérni kódolási módjainkat megalapozó elképzeléseink igazolására.
■ Három megadási mód
Minden gyakorlattal rendelkező PHP programozó tudja, hogy kétféle idézőjel használható PHP-ben karaktersorozatok megadására. Az egyiket - jobb elnevezés híján - dupla idézőjelnek ("), a másikat szimpla idézőjelnek, vagy aposztrófnak (') nevezzük. Az is széles körben ismert, hogy ezen két idézőjelbe zárási mód képességei között jelentős különbségek fedezhetőek fel, mégpedig hogy a dupla idézőjeles karaktersorozatokban változó helyettesítést és speciális karaktereket is alkalmazhatunk, míg aposztróffal zárt sztringek esetén ilyen nem lehetséges. A dupla idézőjelhez hasonlít a heredoc formában megadott karaktersorozat, hiszen a változók értékhelyettesítése itt is működik.
<?php
echo 'Ezt mindegy, hogy hogyan írjuk';
echo "Ezt mindegy, hogy hogyan írjuk";
echo "Itt azonban már egyáltalán nem mindegy\n";
echo 'Itt azonban már egyáltalán nem mindegy\n';
echo <<<VAS
A speciális karakterek itt is működnek.\nDe még mennyire.
VAS;
?>
\n
karaktersorozatot jeleníti meg. A heredoc szabályai szerint a három kisebb jelet követően megadott karaktersorozat kerül a kimenetre, a speciális karakterek pedig a kettős idézőjelhez hasonlóan értelmezésre kerülnek. A háromféle karaktersorozat megadási mód támogatása lehetővé teszi a programozók számára, hogy ne kelljen csúnyán festő megoldásokat választaniuk, ha egy karaktersorozatban a körbezárására használt idézőjelet szeretnék alkalmazni. Egyszerűen csak meg kell változtatni a körbezáró idézőjelet, vagy át kell térni a heredoc jelölésre.
A sebesség hiedelme
Sokáig igaz volt, hogy a kétféle idézőjellel megadott karaktersorozatok feldolgozása között "jelentős" sebesség különbség volt, azaz nagy mennyiségű dupla idézőjeles sztring használata esetén mérhetően lassabb futási időt kaptunk, mint aposztróf használatakor. Ez azonban a ma használatos PHP változatokra már nem igaz (vagy legalábbis teljesen elhanyagolható mértékben igaz), feltéve, hogy literális, speciális karakterektől mentes (azaz további feldolgozást nem igénylő) sztringekről beszélünk. Ugyanezen karaktersorozattal azonban meglepő lassúságot tapasztalhatunk heredoc jelölést használva.Habár kiváló profiler programok állnak rendelkezésre a PHP programok gyenge pontjainak megtalálására, mégsincs speciális kiterjesztésekre szükségünk ahhoz, hogy egyszerűbb méréseket végezhessünk. Az idézőjelekkel kapcsolatos kijelentésekről magunk is meggyőződhetünk a következő egyszerű programmal:
<?php
echo "PHP " . phpversion() . "\n";
// Idő lekérdezésre használt függvény
function getmicrotime()
{
list($usec, $sec) = explode(" ", microtime());
return ((float) $usec + (float) $sec);
}
// ---------------------------------------------
$time_start = getmicrotime();
for ($i=0; $i < 100000; $i++) {
$proba = "ez egy proba karaktersorozat";
}
$time = getmicrotime() - $time_start;
echo "Dupla idézőjelekkel: $time\n";
// ---------------------------------------------
$time_start = getmicrotime();
for ($i=0; $i < 100000; $i++) {
$proba = 'ez egy proba karaktersorozat';
}
$time = getmicrotime() - $time_start;
echo "Szimpla idézőjelekkel: $time\n";
// ---------------------------------------------
$time_start = getmicrotime();
for ($i=0; $i < 100000; $i++) {
$proba = <<<VAS
ez egy proba karaktersorozat
VAS;
}
$time = getmicrotime() - $time_start;
echo "Heredoc megadással: $time\n";
?>
getmicrotime()
kódjára. A microtime()
eléggé finom időmérést tesz lehetővé, legalábbis ehhez a kísérlethez, tekintve, hogy százezerszer lefuttatjuk az értékadásokat. PHP 4.3.4-el és PHP 5.0.0RC1-el a következő kimeneteket kapom Linux alatt:PHP 4.3.4
Dupla idézőjelekkel: 0.48893094062805
Szimpla idézőjelekkel: 0.49282789230347
Heredoc megadással: 1.1971590518951
PHP 5.0.0RC1
Dupla idézőjelekkel: 0.42129611968994
Szimpla idézőjelekkel: 0.42000198364258
Heredoc megadással: 1.0945689678192
Dupla idézőjelekkel: 0.48893094062805
Szimpla idézőjelekkel: 0.49282789230347
Heredoc megadással: 1.1971590518951
PHP 5.0.0RC1
Dupla idézőjelekkel: 0.42129611968994
Szimpla idézőjelekkel: 0.42000198364258
Heredoc megadással: 1.0945689678192
Ez jól láthatóan azt jelenti, hogy a mérés alapján héttized százalékkal (azaz 0,7 százalékkal) gyorsabb a dupla idézőjelek feldolgozása PHP 4.3.4-ben, mint a szimpla idézőjeleké. Ilyen kis feladat esetén azonban nem lehet eltekinteni a futtatás körülményeitől. Különböző mérések eltérő eredményhez vezetnek, a program alapján minden reprodukálható. Tehát ezért nem érdemes áttérni egyik jelölésről a másikra. A heredoc típusú megadás viszont már látványosan lassabb. Azt is láthatjuk, hogy PHP 5.0.0-ban nem túl jelentős sebességváltozás észlelhető, de szerencsére jó irányban.
Mindig vannak kivételek
Legalább akkora hiba lenne most ökölszabálynak azt elfogadni, hogy a két idézőjel használata mindig ugyanarra az eredményre vezet, mint ha azt fogadnánk el, hogy valamelyik gyorsabb. A BlueShoes PHP kerektrendszer fejlesztői oldalán akadtam arra a tippre, miszerint érdemes megnézni a $ karakterek használatakor jelentkező sebesség különbséget.Futtassuk tehát le újra a mérést úgy, hogy most az
ez egy proba $ karaktersorozat $
sztringet helyezzük el a mérésekben, a dollár jelet csak a megtévesztés kedvéért használva. Az most nagyon fontos, hogy vagy a karaktersorozat vége, vagy szóköz szerepel a dollár után, hiszen különben változó hivatkozásnak tekintené a PHP. Nézzük így milyen eredményt kapunk:PHP 4.3.4
Dupla idézőjelekkel: 1.4606549739838
Szimpla idézőjelekkel: 0.4861319065094
Heredoc megadással: 1.5480959415436
PHP 5.0.0RC1
Dupla idézőjelekkel: 1.1676690578461
Szimpla idézőjelekkel: 0.42343306541443
Heredoc megadással: 1.2074928283691
Dupla idézőjelekkel: 1.4606549739838
Szimpla idézőjelekkel: 0.4861319065094
Heredoc megadással: 1.5480959415436
PHP 5.0.0RC1
Dupla idézőjelekkel: 1.1676690578461
Szimpla idézőjelekkel: 0.42343306541443
Heredoc megadással: 1.2074928283691
Mindjárt más. A PHP-nek eléggé sok időt el kell töltenie ebben az esetben azzal, hogy rájöjjön, hogy mi tulajdonképpen nem változót akartunk beilleszteni, hanem magát a dollár jelet, így pedig a dupla idézőjel közel a heredoc mellé szegődik sebességében. Persze ilyenkor körültekintő programozóként sokkal inkább azt kellene írnunk, hogy
ez egy proba \$ karaktersorozat \$
, hiszen ezzel jelezzük, hogy itt most nem változó-érték helyettesítésről van szó. Ezt a megoldást használva sikerül visszatérnünk arra a megállapításra, hogy a két idézőjel sebessége között elenyésző különbség van:PHP 4.3.4
Dupla idézőjelekkel: 0.48207592964172
Szimpla idézőjelekkel: 0.48961210250854
Heredoc megadással: 1.5163249969482
PHP 5.0.0RC1
Dupla idézőjelekkel: 0.43033504486084
Szimpla idézőjelekkel: 0.42638397216797
Heredoc megadással: 1.166738986969
Dupla idézőjelekkel: 0.48207592964172
Szimpla idézőjelekkel: 0.48961210250854
Heredoc megadással: 1.5163249969482
PHP 5.0.0RC1
Dupla idézőjelekkel: 0.43033504486084
Szimpla idézőjelekkel: 0.42638397216797
Heredoc megadással: 1.166738986969
Változók helyettesítése
Nem érdemes azonban itt megállni, ha már úgyis benne vagyunk a mérésben, nézzük meg mi a különbség a változó helyettesítés és a karaktersorozat befűzés között. Megtartva agetmicrotime()
függvényünket, írjuk át a ciklusokat a következőképpen:
<?php
$belso = "proba";
// ---------------------------------------------
$time_start = getmicrotime();
for ($i=0; $i < 100000; $i++) {
$proba = "ez egy $belso karaktersorozat";
}
$time = getmicrotime() - $time_start;
echo "Dupla idézőjelekkel: $time\n";
// ---------------------------------------------
$time_start = getmicrotime();
for ($i=0; $i < 100000; $i++) {
$proba = 'ez egy ' . $belso . ' karaktersorozat';
}
$time = getmicrotime() - $time_start;
echo "Szimpla idézőjelekkel: $time\n";
// ---------------------------------------------
$time_start = getmicrotime();
for ($i=0; $i < 100000; $i++) {
$proba = <<<VAS
ez egy $belso karaktersorozat
VAS;
}
$time = getmicrotime() - $time_start;
echo "Heredoc megadással: $time\n";
?>
proba
szót a $belso
változóval helyettesítettük, amit a dupla idézőjeleknél és a heredoc esetében használható változó helyettesítéssel, valamint az aposztrófoknál alkalmazható karaktersorozat összefűzéssel illesztettünk a helyére. Egy cikk keretében sajnos nem könnyű élni a hatásszünet eszközével és a dobpergés effekttel, ezért kénytelen vagyok rögtön elárulni az eredményt:PHP 4.3.4
Dupla idézőjelekkel: 1.1817910671234
Szimpla idézőjelekkel: 0.80612206459045
Heredoc megadással: 1.2712509632111
PHP 5.0.0RC1
Dupla idézőjelekkel: 1.0963342189789
Szimpla idézőjelekkel: 0.6836302280426
Heredoc megadással: 1.0950348377228
Dupla idézőjelekkel: 1.1817910671234
Szimpla idézőjelekkel: 0.80612206459045
Heredoc megadással: 1.2712509632111
PHP 5.0.0RC1
Dupla idézőjelekkel: 1.0963342189789
Szimpla idézőjelekkel: 0.6836302280426
Heredoc megadással: 1.0950348377228
Kisebb eltérések minden futtatásnál előfordulhatnak, de az arányokon ez nem változtat. Az eredmények azt mutatják, hogy ebben a teszt esetben a változó helyettesítés jelentősen több időbe telik, mint a karaktersorozat hozzáfűzése. Ez azzal magyarázható, hogy a változó nevet meg kell keresni a karaktersorozatban, mely ráadásul kellően bonyolult is lehet (objektum hivatkozással, tömb elemmel), majd pedig ezt helyettesíteni kell az értékével, és csak ezután folytatódhat a feldolgozás. Ebben az egyszerű tesztben hasonló eredményt kapunk, ha a PHP-nek segítünk a változó nevének megtalálásában, azaz
ez egy {$belso} karaktersorozat
kerül az idézőjelek közé, illetve a heredoc belsejébe. Érdekes összehasonlítás, hogy az első mérésünkhöz képest a PHP 4-es kicsit lassabban kezelte a heredoc karaktersorozatot, a PHP 5-ös azonban szinte ugyanazzal a sebeséggel. Ezzel egyenrangú partnerekké lépett elő a dupla idézőjel és a heredoc páros, hiszen PHP 5-ben elenyésző különbség figyelhető meg kettjük között.Tanulság
Úgy gondolom, hogy mindenképpen fontos, hogy az olyan közhiedelmeket, melyekre napi munkánkat építjük magunk is próbáljuk ellenőrizni, legalábbis ha erre lehetőségünk van. Ebben az esetben egy valóban egyszerű mérési lehetőség adott, és mérésünk megnyugtató eredménye lehetővé teszi, hogy ne legyünk paranoiásak a dupla idézőjelekkel szemben, hanem igenis merjük használni, ha ez áll közelebb a megszokott stílusunkhoz. Ugyanakkor érdemes meggondolnunk, hogy változó helyettesítést vagy karaktersorozat összefűzést használunk egy nagyobb alkalmazásban, hiszen ezek sebessége jelentősebb eltérést mutat. Ennek kényszerű megválasztása is csak nagyon nagy alkalmazások esetén szükséges, különben sokkal fontosabb az olvashatósági szempontok figyelembevétele, hiszen hiába gyors a kódunk, ha nem átlátható, és később nehezen fejleszthető. Szintén fontos megjegyezni, hogy az idézőjelek cseréjével egy valós alkalmazásban érezhető sebességnövekedést nem fogunk elérni, hiszen valamilyen távoli szolgáltatás vagy adatbázis használata általában nagyságrendekkel nagyobb mértékben befolyásolja a sebességet. Ha ugyanazt az időt, amit idézőjeleink cseréjére fordítjuk, inkább az adatbázisunk optimalizásával töltjük el, sokkal hálásabbak lesznek látogatóink a gyorsabban működő oldalakat böngészve.Azt is érdemes leszögezni a mérés eredményei alapján, hogy a PHP nemcsak hibajavításokkal és új szolgáltatásokkal jelenik meg verzióról verzióra, hanem az alapvető nyelvi konstrukciók is változnak, fejlődnek (sajnos időnként lassulnak is). Ezért egy általunk végzett mérés tanulságainak időtállóságában sem lehetünk biztosak, érdemes iőnként újra visszatérni kódolási módjainkat megalapozó elképzeléseink igazolására.
Javitas - bar lehet, hogy szorszalhasogatas ;)
Dupla idézőjelekkel: 0.48893094062805
Szimpla idézőjelekkel: 0.49282789230347
Ez jól láthatóan azt jelenti, hogy héttized százalékkal (azaz 0,7
százalékkal) lassabb a dupla idézőjelek feldolgozása PHP 4.3.4-ben, mint a
szimpla idézőjeleké. Tehát ezért nem érdemes áttérni az aposztrófokra.
---
Szerintem itt gyorsabb ennyivel, nem lassabb. Bar lehet, hogy tobbszor
lefuttatva lehetne lassabb is... :)
Teljesen igaz
teszt mashol
megoldas... (CELERON P4 1,7G)
PHP 4.3.1
Dupla idézőjelekkel: 0.32194399833679
Szimpla idézőjelekkel: 0.23652577400208
Heredoc megadással: 0.38350009918213
Dupla idézőjelekkel: 0.31602478027344
Szimpla idézőjelekkel: 0.22558093070984
Heredoc megadással: 0.31760406494141
Dupla idézőjelekkel: 0.31773710250854
Szimpla idézőjelekkel: 0.22830104827881
Heredoc megadással: 0.33787488937378
Udv: Attila
Verziófüggő
Csak a valtozatossag kedveert...
Dupla idézojelekkel: 0.283003091812
Szimpla idézojelekkel: 0.118773937225
Heredoc megadással: 0.28635597229
Milyen gépen?
-boogie-
Laptop p3[1ghz] 512 ram
Valtozo $proba = "ez $belso...";
Dupla idézőjelekkel: 0.709594011307
Szimpla idézőjelekkel: 0.28307890892
Heredoc megadással: 0.738415956497
Elnevezés
Tudtommal (legalábbis nyelvésztől olvastam) az egyik (a kettős) az idézőjel, a másik a hiányjel (nyelvtani - nem keverendő össze a számtanival).
attól függ