Utolsó frissítés: 2012.02.13.
Facebook Twitter iWiW MySpace Digg Delicious Google bookmarks Startlap Windows Live

Függvények II.

Beépített függvények használata

Az előző leckében megtanultuk, hogyan készíthetünk függvényeket, melyek főleg arra szolgálnak, hogy a gyakran elvégzendő feladatokat beleírjuk, majd ahol az adott feladatot el kell végezni, egyszerűen meghívjuk a függvényt. Nyilván sok olyan, gyakran elvégzendő feladat van a PHP-ben, melyekre nincsenek definiálva nyelvi elemek, amik közvetlenül elvégzik az adott feladatot. Sok probléma van ezek között, melyek bonyolultak, vagy magasabb szintű ismeretek szükségesek a megoldásukhoz. Így a PHP-ben (ahogy a legtöbb más nyelvben is) beépített függvények állnak rendelkezésünkre a gyakoribb feladatok gyors és egyszerű elvégzésére. A beépített függvények ugyanúgy működnek, mint az általunk készítettek, csak nem kell őket definiálnunk, mert azt már mások megtették helyettünk. Ezeket a PHP kódunkban bárhol meghívhatjuk, csak a használatukat kell megtanulni. Egyébként a PHP nyelvben a beépített függvények száma ezres nagyságrendű :D. Nyilván nincs élő ember aki mindet ismeri (persze lehet hogy tévedek), és a legtöbb függvényt fölösleges is ismerni. Ha egy speciális feladatot kell elvégezni, akkor az ember megnéz egy referenciát, ahol az összes megtalálható (pl. www.php.net, ami a hivatalos referencia), és ott le van írva hogyan kell használni. Az igazán gyakran használt függvények száma talán 15-20 lehet, ezen a tanfolyamon nem is fogunk ennél többet megismerni. Ha PHP-ben akarunk programozni, akkor ezek használatát mindenképp érdemes elsajátítani, nem lehet csak referenciákra támaszkodni.
Tulajdonképpen már három beépített függvényt ismerünk is valamilyen szinten, az egyik pedig talán már a könyökünkön jön ki. Többször történt említés egy bizonyos exit(); parancsról, és talán egyeseknek feltűnt, hogy ez pont úgy néz ki, mint egy paraméter nélküli függvény hívása. Ezenkívül, esetleg valaki még emlékszik, a logikai operátoroknál szerepelt az egyik példában egy bizonyos isset($változó) alakú dolog, aminek a helyére true logikai érték kerül, ha a zárójelbe írt változó létezik. Most már világosan látszik, hogy ez és az exit is függvények, csak akkor nyilván nem említhettem ezt a kifejezést. Sőt, a "kiírás" feladatát elvégző print utasítás (ez az, ami a könyökünkön jön ki) szintén függvény! Ez azonban itt nem olyan nyilvánvaló, mivel hiányoznak a kerek zárójelek, hogy miért, azt hamarosan megtudhatod. Ebben a leckében ugyanis részletesebben megismerhetjük ezt a három függvényt, és mellette még további hármat is!

print()

A print valójában egy nyelvi elem (mivel a többi nyelvi elem segítségével nem valósítható meg), csak függvényként is használható, ezért szokták függvénynek nevezni. Ez azt jelenti, hogy használható a kerek zárójelekkel is, vagyis például az alábbi két sor egyenértékű:

	print "szöveg";
	print("szöveg");

Az hogy valami egy nyelvi elem, azt jelenti, hogy nem a PHP nyelvtől függetlenül van megalkotva, hanem bele van építve, mint például a while utasítás, vagy az if-else szerkezet.
A print-nek egy karakterlánc paramétere van, amit beír a HTML kódba (ez a függvény mellékhatása). Visszatérési értéke egy logikai érték (true vagy false) attól függően, hogy sikerült-e kiírni a karakterláncot vagy nem. Természetesen ennél a függvénynél a mellékhatás a lényeg, nem a visszatérési érték.
A print függvényen kívül van még olyan, ami a kerek zárójelek nélkül is hívható: az echo. Ez ugyanazt csinálja, amit a print, és ugyanúgy is kell használni. Különbség az, hogy ennek nincs visszatérési értéke. Vagyis a fenti két sorral ezek is egyenértékűek:

	echo "szöveg";
	echo("szöveg");

Én a példaprogramokban továbbra is a print-et fogom használni a kiírásra, de persze mindenki ízlésének megfelelően választhat a két függvény közül (ilyet nem először írok, a PHP nyelv úgy látszik nagyon felhasználóbarát :D).
Valójában bizonyos más, függvényként is használható nyelvi elemek is használhatók zárójelekkel és zárójelek nélkül egyaránt: például a return nyelvi elem használható zárójelekkel is, de ezt általában nem szokták függvénynek tekinteni. Ellenben az isset valójában nyelvi elem, de nem használható zárójelek nélkül. Az, hogy egy utasítás függvény-e vagy nyelvi elem, a legtöbb esetben teljesen lényegtelen, így a továbbiakban nem foglalkozunk ezzel. Általában a return, print és echo esetében nem használnak zárójelet, a többi esetében igen. Érdemes ezt a terminológiát követni.

strlen()

Az strlen() gyakran használt függvény, ami egy karakterlánc hosszát adja meg ("string lenght" kifejezésből származik a neve). Egy paramétere van, aminek karakterláncnak kell lenni, visszatérési értéke egy egész szám, ami a paraméterként átadott karakterlánc hossza (vagyis az, hogy hány karakterből áll). A függvénynek nincs mellékhatása. Példák:

	strlen("szöveg");    // 6
	$s = "php";
	strlen($s);          // 3
	strlen("html".$s);   // 7
	strlen("");          // 0

A fenti megjegyzések a visszatérési értéket mutatják.

isset()

Ez a függvény megvizsgálja, hogy létezik-e a paramétereként átadott változó. Paramétere bármilyen típusú változó lehet, és ha a változó létezik, true értéket ad vissza, egyébként false-t. Egy változó onnantól kezdve létezik, hogy értéket adtunk neki. Egy változót lehet törölni is, például úgy, hogy null értéket adunk neki.

	// még nem szerepelt a kódban az $n változó...
	isset($n);    // false
	$n = 5;
	isset($n);    // true
	$n = null;
	isset($n);    // false

A null érték nem tartozik egyik, eddig tanult típusba sem (nem szám, karakterlánc, vagy logikai érték), mivel pont azt jelzi, hogy a változó nem tárol semmilyen értéket. A null-t felfoghatjuk egy olyan kulcsszónak, mint például a while. Az üres karakterlánc egyébként nem egyenértékű ezzel, ha a változó egy üres karakterláncot tárol, az isset true értéket ad vissza!
Jelenleg ez nem tűnik túl hasznos függvénynek, az űrlapok kiértékelésénél fogjuk hasznát venni.

exit()

Az exit() függvény hatására a program futása megszakad. Ha meghívódik, akkor olyan a hatása, mintha az alatta lévő sorok ott se lennének (se PHP, se HTML). Átadható neki paraméterként egy karakterlánc, amit a program megszakítása előtt kiír, ez például hibaüzenetként jól használható. Ha nem adunk át neki paramétert, nem ír ki semmit. Ez elég furcsának tűnik, a 14. leckében lesz szó arról, hogy írhatunk ilyen függvényt. Visszatérési értéke nincs. Példát most nem írok, már láttuk korábbi leckékben működés közben.

time()

Ez a függvény nem fogad paramétert, visszatérési értéke egy nagy egész szám. A hívás időpontjában visszaadja az 1970. január 1. 00:00:00 óra óta eltelt másodpercek számát. Elsőre ez hülyeségnek tűnhet, de például két egymás utáni hívás esetén a visszatérési értékek különbsége a hívások között eltelt másodpercek számát adja meg, így bizonyos esetekben használható időmérésre. Példát a következő függvény ismertetésében láthatunk.

date()

Az eddigi függvények eléggé egyszerűek voltak, ez egy bonyolultabb, viszont annál hasznosabb. Ezzel ember számára olvasható formává tudjuk pofozni a time() által visszaadott értéket. Az első paramétere egy karakterlánc, a második egy egész szám, ahova az 1970 óta eltelt másodperceket kell írni. Ha a jelenlegi dátumot akarjuk vele kiíratni, akkor nyilván a time() által visszaadott értéket kell második paraméterként megadni:

date("...", time());

A visszatérési értéke egy karakterlánc, amiben a dátum kívánt formája található. A kívánt formát az első paraméterrel állíthatjuk be. Ez egy karakterlánc, amiben bizonyos karaktereknek speciális jelentése van. Például az "Y" karakter az aktuális évet jelenti. Minden egyes speciális karakter az ember számára olvasható információt ad az időről. A fontosabbak:

	Y : év (pl. 2008)
	m : hónap (pl. 04)
	d : nap (pl. 09)
	H : óra (pl. 15)
	i : perc (pl. 02)
	s : másodperc (pl. 00)

Itt például perc alatt nyilván nem az 1970 óta eltelt percek számát kell érteni, hanem hogy az adott óra hanyadik percében vagyunk. Ha például dél van, akkor a perc értéke 00. A függvény úgy működik, hogy az első paraméterét adja vissza, csak a benne szereplő speciális jelentésű karakterek helyére a neki megfelelő érték kerül a visszatérési értékként átadott karakterláncban.
Például tegyük fel, hogy 2008. szeptember 3. az aktuális dátum, az idő pedig délután 4 óra 10 perc 46 másodperc! Ekkor az alábbi alakban hívva a függvényeket a megjegyzésként utána írt karakterláncokat gyártja le:

	$t = time();         // ez a változó lesz a második paraméter
	date("Y", $t);       // "2008"
	date("H", $t);       // "16"
	date("m", $t);       // "10"
	date("Y.m.d", $t);   // "2008.10.03"
	date("H:i:s", $t);   // "16:10:46"
	date("d-m-Y", $t);   // "03-10-2008"

A megjegyzésekben a visszatérési értékek szerepelnek. Látható, hogy a betűk helyére a megfelelő adatok kerülnek (bizonyos formában, pl. a hónap helyére a 10-es szám), az írásjelek (pont, kettőspont, kötőjel) viszont változatlan formában kerülnek a karakterláncba. Ha a karakterláncba nem idővel kapcsolatos adatokat is bele akarunk helyezni, akkor csak írásjeleket használjunk, mert kb. 30-féle speciális jelentésű karakter van, és ezeket csak bonyolult módon tudjuk beleírni a visszatérési értékbe. Ha például "16 óra 10 perc 46 másodperc" alakban szeretnénk megkapni az aktuális időt, akkor azt így tehetjük meg:

	$t = time();
	$ora = date("H", $t);
	$perc = date("i", $t);
	$masodperc = date("s", $t);
	$ido = $ora." óra ".$perc." perc ".$masodperc." másodperc";

Itt csak az adott időpontra vonatkozó adatokat nyertük ki a date() függvény segítségével, majd ezekből utólag felépítettük a kívánt formátumot. Persze lehet olyan óhajunk is, hogy például az órát nem 16 hanem 4 óra alakban szeretnénk megkapni. Erre alkalmas például az első paraméterben a "h" betű, de ha ezt nem tudjuk, és nem akarunk referenciákban keresgélni, akkor a "H" által létrehozott értékből is kinyerhetjük:

	$ora = date("H", time());
	$perc = date("i", time());
	if ($ora > 12){
		$ora -= 12;
		$de_du = "Délután ";
	}
	else{
		$de_du = "Délelőtt ";
	}
	print $de_du.$ora." óra ".$perc." perc van!";

Emlékeztetőül, a -= értékadó operátor operátor jelentése itt az, hogy az $ora értékéből 12-t levonunk, vagyis az adott sor így is írható: $ora = $ora - 12;. Extra szolgáltatásként egy $de_du változóban eltároljuk azt, hogy éppen délelőtt vagy délután van-e. Így például a fent említett időpontban a program ezt írja ki:
Délután 4 óra 10 perc van!
Fontos megjegyezni viszont, hogy a program nem tökéletes (úgy is mondhatnám hogy hibás), ugyanis vannak olyan időpontok, amikor nem jól működik. Már megint képtelen voltam normális programot írni! :) Sokszor előfordul, hogy egy első nekifutásra írt kódról kiderül, hogy egyes speciális esetekben nem jól működik, és ki kell javítanunk. Hogy ezt az élményt is átélhessük, a hiba megtalálása és kijavítása most házi feladat lesz!
Persze van olyan, dátumra vonatkozó adat, amit nem tudunk kinyerni a fenti hat speciális karakterrel, például hogy a hét melyik napja van (hétfő, kedd, stb). Pontosabban ezt is ki lehet deríteni, csak nagy erőfeszítések kellenek hozzá. Látható, hogy ez már egy bonyolult függvény, aminek a teljes kihasználásához nem árt egy referencia. Például az ezen az oldalon lévő referenciában (egészen pontosan itt) megkereshetjük, hogyan lehet kideríteni a segítségével, hogy a hét milyen napja van ma (bár egy későbbi leckében benne lesz a megoldás).

A date() függvényt nem elrettentésül raktam ide példaként, hanem mert segítségével tényleg hasznos dolgokat tudunk csinálni, sőt, bizonyos értelemben segítségével már a HTML lehetőségein túlmutató weboldalt is készíthetünk. Például próbáljuk ki, hogy egy weboldalba beszúrjuk az alábbi php blokkot:

	<?php
	print date("H:i:s", time());
	?>

Valahányszor az oldalra frissítünk, a PHP kód az aktuális időt fogja kiírni, így minden frissítésnél más fog megjelenni. Így bizonyos értelemben dinamikus lett az oldalunk. A PHP-vel elérhető dinamikusság viszont nem azt jelenti, hogy egérkattintásra beúszó menüt, vagy a böngésző ablakában röpködő képeket tudunk majd csinálni. Az ilyesmire a JavaScript, durvább esetekben a Flash használható. A PHP arra való, hogy a weboldalt "dinamikusan állítsa elő", nem pedig hogy "mozgassa". Gondolhatunk például egy fórumra: egy fórum dinamikus, mert ha írunk egy szöveget a megfelelő helyre, majd megnyomunk egy gombot, akkor egy korábban látott oldal jelenik meg, csak már mást láthatunk rajta (rajta lesz az általunk írt szöveg). A fenti kis program esetében hasonlót láthatunk, csak nagyon leegyszerűsített formában.

Házi feladat

1.) Keressük meg az utolsó előtti példaprogramban az említett hibát, és próbáljuk meg kijavítani!

Megoldás

Az ominózus példaprogram:

		$ora = date("H", time());
		$perc = date("i", time());
		if ($ora > 12){
			$ora -= 12;
			$de_du = "Délután ";
		}
		else{
			$de_du = "Délelőtt ";
		}
		print $de_du.$ora." óra ".$perc." perc van!";

Az egyetlen hiba, hogy a program szerint, ha $ora > 12 akkor délután van, egyébként pedig délelőtt. Vagyis délután 13:00-tól van, de ez nyilván hülyeség. A 12:xx alakú időpontok elé is délutánt kéne írni. Hogy tudjuk ezt kijavítani? Nyilván lehetne úgy, hogy az if ág belsejébe egy elágazást rakunk, de átláthatóbb lesz a program, ha a fenti if-else szerkezetet egy háromágú else-if szerkezetté alakítjuk. Például így:

		$ora = date("H", time());
		$perc = date("i", time());
		if ($ora > 12){
			$ora -= 12;
			$de_du = "Délután ";
		}
		else if ($ora == 12){
			$de_du = "Délután ";
		}
		else{
			$de_du = "Délelőtt ";
		}
		print $de_du.$ora." óra ".$perc." perc van!";

Egyszerűen be lett szúrva egy else if ág, ami a problematikus 12:xx alakú időpontokat kezeli.

2.) Mérjük le a time() függvény segítségével a prímszámkilistázó program sebességét! Állítsuk be, hogy írja ki az első 10000 prímszámot, és írassuk ki a végére, hogy ez hány másodpercig tartott! (Nyilván a PHP kód elején és végén érdemes meghívni a függvényt, majd a visszatérési értékeket felhasználni)
Hogyan tudnánk elérni, hogy a prímszámok listája elé írja ki az eltelt időt?

Megoldás

A prímszámkilistázó program a 10. lecke elején található, a helyére most csak egy megjegyzést írok. A time() két hívása közti időkülönbség nyilván a visszatérési értékek különbsége lesz (másodpercben):

		$eleje = time();
		//prímlistázó program
		$vege = time();
		print ($vege - $eleje)." másodperc telt el!";

Ha a lista elé akarjuk kiíratni az eltelt időt, akkor a prímlistázó programot kell módosítani úgy, hogy ha talált egy prímet, akkor azt ne írja ki, hanem fűzze hozzá egy karakterlánchoz, majd miután kiírtuk az időt, ezt a karakterláncot kiírjuk:

		$eleje = time();

		$primek = "";
		$szam = 1;
		while ($szam < 10000){
			$prim = true;
			$x = 2;
			while ($x <= ($szam / 2)){
				if ($szam % $x == 0){
					$prim = false;
					$x = $szam;
				}
				++$x;
			}
			if ($prim == true){
				$primek .= $szam.", ";     // ez a sor változott
			}
			++$szam;
		}

		$vege = time();
		print ($vege - $eleje)." másodperc telt el!";
		print "<br /><br />".$primek;