Adattípusok konverziója PHP-ben

Az Adattípusok PHP-ben című leírásban végignéztük, hogy egy-egy kifejezés milyen típusú lehet; néhány helyen jeleztem, hogy majd lesz szó a típus-konverzióról is, mert ez egy fontos – ám sajnos szintén gyakran elfeledett – témakör.

A PHP nem teszi lehetőve a kifejezések típusának explicit meghatározását. Akinek ez a mondat most nem teljesen egyértelmű egy egyszerű C program példáján elmagyaráznám:

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;
int main()
	{
	int szam = 5;
	cout << "Helo Vilag!" << szam;
	return 0;
	}

A kód részletezésébe nem mennék bele, össz-vissz a “Helo Vilag!5” szöveget írja ki a képernyőre. Két – számunkra most fontos – dologra hívnám fel a figyelmet:

1
2
int main()
int szam = 5;

Mindkét sorban ismétlődik az int kifejezés. Ez határozza meg a kifejezés (itt: függvény (main) és változó (szam)) lehetséges értékkészletét: egész számok.

A fenti kódban például a main() nem térhet vissza csak egész számmal, a szam változóban pedig nem tárolhatunk pl. karakterláncot. Egy kicsit módosítva a kódot azonban igen.

1
	char szam[12] = "Helo Vilag!";

Ekkor már a szam változónk a “Helo Vilag!” karakterláncot tartalmazza, így a “Helo Vilag!” kifejezés már kétszer kerül a képernyőre. Ehhez azonban meg kellett változtatnunk a változó típusát int-ről char-ra.

Nos, ilyen nincs a PHP-ben, mivel az nem támogatja az explicit típus-meghatározást: a változóink típusa legtöbbször azok tartalmától függ. Ez persze azt eredményezi, hogy állandóan ellenőrizgetnünk kell, hogy adott változó tartalma bizonyos típusba tartozik-e. Másik megoldásként átalakíthatjuk a megfelelő típusra, ha ismerjük a konverziók következményeit.

A különböző típusok között több módszerrel is konvertálhatunk, ezek közül a legegyszerűbb, hogy a kívánt típus nevét zárójelben a kifejezés elé tesszük. Például:

1
2
$foo = 12;
$foo = (string)$foo; /* foo mostantól karakterlánc típusú, értéke "12" */

Használhatunk továbbá átalakító függvényeket (intval, floatval, strval, settype), és jónéhány egyéb megoldást (pl.: idézőjelben használt érték karakterlánccá alakul)

A PHP rengeteg esetben automatikusan elvégzi ezeket a konverziókat (pl.: érték-összehasonlító operátorok használatakor (== és !=), függvények paraméterezésekor, …), így még fontosabb, hogy tisztában legyünk ezzekkel a szabályokkal.

Mondok egy példát:

1
('http://www.tutorial.hu/node/989' == true);

Ez a kifejezés igaz-ként fog kiértékelődni, annak ellenére, hogy ezen cikk url-e nem igazán egyezik meg a bool igaz értékkel. Azonban – az automatikus konverzió miatt – a nem üres karakterlánc (lásd később!) igazként értékelődik ki, így az egyenlőség igaz lesz. Amennyiben ez nem az elvárt működés, használhatjuk az érték és típus-összehasonlító operátorokat (=== vagy !==).

Összehasonlító operátorok a PHP kézikönyvben

Nézzük is végig típusonként, hogy mi miként értékelődik ki, bizonyos típussá alakítva!

A leírás során az adatok hitelességét ellenőrizendő mindig a következő szkriptet használom, gyorsan lehet vele ellenőrizni az állításaim:

1
2
3
4
5
6
7
8
<?php
$foo = ;
var_dump((bool)$foo);
var_dump((int)$foo);
var_dump((float)$foo);
var_dump((string)$foo);
var_dump((array)$foo);
var_dump((object)$foo);

A $foo változó természetesen mindig a vizsgálni kívánt típusba tartozó értéket kell, hogy hordozzon.

Null

A null érték bármivé alakítva hamis-ként (0 v. üres sztring, tömb, objektum) kerül kiértékelésre, mivel ez ugye egy adat hiányát jelöli.

Bool

Az adattípus egyszerűségét tekintve a konverzió sem túl bonyolult. A True (igaz) érték 1-ként, a False (hamis) érték 0-ként értékelődik ki.

Skalár értékké (egész szám, lebegő pontos szám, karakterlánc) alakításkor 0-val ill. 1-el megegyező értéket vesz fel (az új adattípussal).

Tömbbé alakításkor a 0. indexű tömbelem egy boolean false v. true értéket fog tárolni. Objektummá alakításkor egy StdClass osztályba tartozó objektum jön létre, melynek scalar tulajdonsága lesz – továbbra is boolean típusú – igaz v. hamis.

Integer

Szintén egyszerű az átalakítás folyamat. Boolean típussá alakításakor a 0 értékű integer értékelődik ki false-ként, minden más esetben igaz-ként értékelődik ki.

1
2
3
4
var_dump((bool)515); /* bool(true) */
var_dump((bool)1); /* bool(true) */
var_dump((bool)-13); /* bool(true) */
var_dump((bool)0); /* bool(false) */

Lebegőpontos és karakterlánc értékké alakításakor értéke ugyanaz az egész szám marad, csak típusa változik.

Tömbbé és objektummá alakításkor szintén a 0. indexű elem és az StdClass osztály scalar tulajdonsága tartalmazza az int típusú értéket.

Lebegőpontos számok

A bool típussá alakítás mikéntje megegyezik az integerével. Integer típussá alakításakor az érték egész részét veszi fel.

1
2
3
var_dump((int)515.12); /* int(515) */
var_dump((int)1.1); /* int(1) */
var_dump((int)-13.24); /* int(-13) */

Karakterláncá alakításkor csak a típusa változik, tömbbé és objektummá alakításkor szintén a 0. indexű elem és a scalar tulajdonság tárolja az értéket (amely itt float típusú lesz)

Karakterláncok

A karakterláncok átalakítása már kissé problémásabb…

Boolean értékké kovertáláskor az üres karakterlánc (“”) értékelődik ki hamisként, a nem üres karakterláncok pedig igazként.

Integerré és lebefőpontos számmá alakítás egy fokkal bonyolultabb.
Először minden láthatatlan (whitespace) karaktert eltüntet a karakterlánc elejéről (mint az ltrim függvény). Ezután a karakterlánc elejétől sorra végigveszi a karaktereket, az első nem szám és pont (jelen esetben a tizedesvessző) karakterig, majd ezt az értéket adja vissza (Egész számnál csak szám).

Bonyolultan hangzik, talán egy példán keresztül jobban érthető lesz:

1
2
3
$szoveg = "\t\t\r\n\t12.432Akkor itt még legyen egy kis 3l33t sz0v3g";
var_dump((int)$szoveg); /* int(12) */
var_dump((float)$szoveg); /* float(12.432) */

A \t, \r és \n a tabulátor és újsor karakterek, amelyek whitespace karakternek minősülnek, így nem kerülnek értelmezésre. Ezután jön a 12, majd egy pont. A pont megszakítja az egészszámmá alakítást, így lesz ez az érték 12. Mikor lebegőpontos számmá alakítjuk tovább halad és az első nem-numerikus értéknél (A) áll meg. A tizedes-vessző után már újabb pontnál szintén megszakad az alakítás, például:

1
2
$szoveg = "12.432.423";
var_dump((float)$szoveg); /* float(12.432); */

Tömbbé és objektummá konvertáláskor szintén a 0. indexű elem és scalar tulajdonság tartalmazza az értéket.

Tömb

A tömbök átalakítása sem túl probléma-mentes.

Bool típussá alakításkor az üres tömb hamis, míg a nem üres tömb igaz értékké alakul. Integerré és egész számmá alakításkor az elv hasonló, csak az értékeknek megfelelő 0 ill. 1 értékekkel. Karakterlánccá alakításkor mindig az Array karakterláncként fog kiértékelődni.

A probléma az objektummá alakításkor van. Ilyenkor szintén az StdClass egy példányává alakul, ám a korábbiaktól eltérően nem egy tulajdonság tartalmazza az értéket, hanem a kulcs => érték párosok alakulnak tulajdonság => érték párosokká. Például:

1
2
3
$auto = array('company' => 'Ford', 'modell' => 'T-Modell', 'year' => 1908);
$auto = (object)$auto;
print 'A ' . $auto->company . ' ' . $auto->modell . ' gyártása ' . $auto->year . '-ben kezdődött el.';

Ez – ahogy elvárjuk – az “A Ford T-Modell gyártása 1908-ben kezdodött el.” szöveget fogja kiírni. A probléma az indexelt tömböknél jön elő: a PHP-ben az $objektum->0 szintaxis hibát generál, így nem használható. Azonban – egy kerülő megoldással – ezeket is elérhetjük:

1
2
3
4
$autok = array('T-modell', 'Galaxie');
$autok = (object)$autok;
$x = 0;
print 'Ford ' . $autok->$x;

Folytonos számozás esetén ismeretlen számú elemet is végignézhetünk:

1
2
3
4
5
6
7
8
$autok = array('T-modell', 'Galaxie');
$autok = (object)$autok;
$x = 0;
while(IsSet($autok->$x))
   {
   print 'Ford ' . $autok->$x;
   $x++;
   }

(Ez a probléma a PHP 5-ben az objektumokra is elérhetővé tett foreach-el megszűnik)

Objektumok

Objektumokra is érvényesek a tömböknél leírt szabályok, ám ezek átalakítása már problémamentesebb.

Üres – tulajdonságokkal nem rendelkező – objektumok false-ként (ill. 0-ként) értékelődnek ki bool, int valamint float konverziókor. Azonban lássuk be, ez ritka eset.

1
2
3
4
5
6
7
8
9
10
class foo { }
$foo = new foo();
var_dump((bool)$foo); /* bool(false) */
class fooBar extends foo { var $bar; }
$foo = new fooBar();
var_dump((bool)$foo); /* bool(true) */
$foo = new stdClass();
var_dump((bool)$foo); /* bool(false) */
$foo->bar = 'FooBar';
var_dump((bool)$foo); /* bool(true) */

Mint látható amint van valamilyen tulajdonság (a második esetben a fooBar osztály $bar tulajdonsága, a negyedikben az StdClass osztályú objektumhoz rendelt bar tulajdonság) igazként (1) értékelődik ki az objektum átalakítás után.
Karakterlánccá alakításkor az “Object” szöveggé alakulnak az objektumok.

A PHP 5 bevezetett egy mágikus metódust, a __toString()-et. Ha közvetlenül print-el vagy echo-val használjuk az objektumot, akkor a __toString meghívásra kerül, és a visszaadott érték kerül a kimenetre. Fontos azonban megjegyezni – mint ahogy a kézikönyvben is kifejtik a példákkal -, hogy csak közvetlenül meghívva, és csak az echo ill. print nyelvi elemnél működik ez a mágikus metódus.

1
2
3
4
5
6
7
8
9
10
class foo()
	{
	function __toString()
		{
		return 'Bar';
		}
	}
$foo = new foo();
print $foo;
print (string)$foo;

Ez PHP 4 alatt az “ObjectObject” szöveget írja ki, míg PHP 5 alatt a “BarObject id #1” kimenetet adja. Itt is használhatunk kerülő megoldásokat, ezek közül egy:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function oOutPut()
	{
	$array = func_get_args();
	while(list($key, $value) = each($array))
		{
		if(!Is_object($value))
			{
			print (string)$value;
			}
		else
			{
			if(method_exists($value, '__toString'))
				{
				print $value->__toString();
				}
			else
				{
				print "Object";
				}
			}
		}
	}

Ez a kód PHP 4 és 5 alatt egyaránt működik, és mindenhol ugyanazt fogja visszaadni (nincs több Object id! :P ). Ráadásul a sima print-es ill. echo-s megoldásnál – bár lassabb – jobban használható.

1
2
3
4
5
6
7
8
9
10
class ize
	{
	function __toString()
		{
		return 'Én egy izé vagyok';
		}
	}
$foo = new ize();
$bar = new StadClass();
oOutPut('$foo mondja:', $foo, '$bar mondja:', $bar);

A kimenete: “$foo mondja:Én egy izé vagyok <br>$bar mondja:Object” lesz PHP 4 és 5 alatt egyaránt.

Az objektumok tömbbé alakítása már jóval egyszerűbb, a tulajdonság = érték párosok kulcs => érték párosokká alakulnak.

Ezzel rövid (?) összefoglalónk végére értünk, a következőben kifejtem, hogy ezeket hol és mire tudjuk kihasználni, és hol érdemes figyelni az automatikus konverzió eredményeire…

HOZZÁSZÓLOK A CIKKHEZ

Kérjük, írja be véleményét!
írja be ide nevét