PHP kézikönyv
Előző | 12. Fejezet. Változók | Következő

# Változók hatásköre

[Ezt a fejezetet érdemes elolvasni, még akkor is, ha profi vagy valamilyen programozási nyelvben, mert a PHP tartogat egy-két érdekes meglepetést...]

A változó hatásköre az a környezet, amelyben a változó definiált. A legtöbb esetben minden PHP változónak egyetlen hatásköre van. Ez az egyetlen hatáskör kiterjed az include és a require segítségével használt fájlokra is. Például:

`<?php $a = 1; include 'b.inc'; ?>`

Itt az $a változó elérhető lesz az beillesztett `b.inc` szkriptben is. A felhasználói függvényekkel a lokális függvényhatáskör kerül bevezetésre. Alapértelmezés szerint minden, függvényen belül használt változó ebbe a lokális függvényhatáskörbe tartozik, például:

`<?php $a = 1; /* globális hatáskör */ function Test () { echo $a; /* egy helyi változót vár */ } Test(); ?>`

Ez a szkript nem fog semmilyen kimenetet sem eredményezni, mivel az echo kifejezés az $a változónak egy helyi - függvényen belüli - változatára utal, és ebben a hatáskörben ehhez nem rendeltek értéket. Ez valamelyest különbözik a C nyelv filozófiájától, ahol a globális változók automatikusan elérhetők bármely függvényből, feltéve ha a függvényben újra nem definiáltad azt a változót. Ez problémák forrása lehet, ha az ember véletlenül megváltoztat egy globális változót. A PHP-ben a globális változókat global kulcsszóval kell deklarálni a függvényekben.

## A global kulcsszó

Először nézzünk egy példát a global használatára:

Példa 12-1. A global használata

`<?php $a = 1; $b = 2; function Osszead() { global $a, $b; $b = $a + $b; } Ossszead(); echo $b; ?>`

A fenti szkript kiírja, hogy "3". $a és $b global-ként való deklarálásával minden utalás ezekre a változókra a globális változót fogja érinteni. Nincs megkötve, hány globális változót kezelhet egy függvény.

Globális változók elérésének másik módja a PHP által definiált speciális $GLOBALS tömb használata. Az előbbi példával egyenértékű megoldás:

Példa 12-2. A $GLOBALS használata global helyett

`<?php $a = 1; $b = 2; function Osszead() { $GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b']; } Osszead(); echo $b; ?>`

A $GLOBALS asszociatív tömb, ahol a globális változó neve jelenti a kulcsot, és a változó értéke a tömbelem értéke. Vedd észre, hogy a $GLOBALS tömb minden hatáskörben létezik, mivel a $GLOBALS egy szuperglobális változó. A következő példa a szuperglobális változók erejét szemlélteti.

Példa 12-3. Példa szuperglobális változók és a hatáskör szemléltetésére

`<?php
function global_teszt()
{
// A legtöbb előredefiniált változó nem "szuper" és
// megkövetelik a 'global' használatát, hogy elérhetőek
// legyenek függvények helyi hatáskörében.
global $HTTP_POST_VARS;
echo $HTTP_POST_VARS['nev'];
// A szuperglobális változók elérhetőek bármilyen
// hatáskörben, és nem szükséges a 'global' kulcsszó.
// A szuperglobális változók a PHP 4.1.0-től használhatóak,
// a HTTP_POST_VARS pedig már elavultnak számít.
echo $_POST['nev'];
}
?>`

## Statikus változók használata

A változók hatáskörének másik fontos lehetősége a static (statikus) változó. A statikus változó csak lokális hatáskörben él - egy függvényen belül, de két függvényhívás közt nem veszti el az értékét, a változó hatásköréből való kilépés esetén is megmarad az értéke:

Példa 12-4. Statikus változók szükségességét szemléltető példa

`<?php function Test() { $a = 0; echo $a; $a++; } ?>`

Ez nagyon haszontalan függvény, mivel nem csinál mást, mint minden meghívásakor $a-t 0-ra állítja, aztán kiírja a 0-t. Az $a++ teljesen felesleges, mert amint vége a függvény futásának az $a változó megszűnik. Ahhoz, hogy ebből értelmes számlálófüggvény legyen - megmaradjon a számláló értéke -, az $a változót statikusnak kell deklarálni:

Példa 12-5. Példa statikus változók használatára

`<?php function Test() { static $a = 0; echo $a; $a++; } ?>`

Most már valahányszor meghívódik a Test() függvény, kiírja $a értékét, majd azt megnöveli eggyel.

A statikus változókat a rekurzív függvények megvalósításában is felhasználhatjuk. Rekurzívnak nevezzük azt a függvényt, amely saját magát hívja meg. Ezt természetesen feltételhez kell kötni, nehogy végtelen rekurzióba kerüljön a vezérlés és meghatározatlan időre a függvényen belül csapdába esik. Mindig meg kell bizonyosodni arról, hogy megfelelő feltétel rendelkezésre áll a rekurzió befejezéséhez. A következő függvény rekurzívan elszámol 10-ig a statikus $count változó segítségével: [A static kulcsszó nagyon fontos!]

Példa 12-6. Statikus változók rekurzív függvényekkel

`<?php function Test() { static $count = 0; $count++; echo $count; if ($count < 10) { Test(); } $count--; } ?>`

> Megjegyzés: Statikus változókat a fenti példákban szereplő módon lehet deklarálni. Ha olyan értéket próbálsz értékül adni neki, amely egy kifejezés eredménye, az parse error-t fog okozni.

> Példa 12-7. Statikus változók deklarálása

> `<?php function ize(){ static $int = 0; // jó static $int = 1+2; // rossz (mivel ez egy kifejezés) static $int = sqrt(121); // rossz (szintén kifejezés) $int++; echo $int; } ?>`

## Referenciák globális és statikus változókkal

A PHP 4-et működtető Zend Engine 1, a statikus és globális változó módosítókat referenciákkal implementálja. Például egy valódi globális változó beemelve egy függvény hatáskörébe a global utasítással tulajdonképpen létrehoz egy referenciát a globális változóhoz. Ez váratlan viselkedésmódhoz vezethet, amelyet a következő példa illusztrál:

`<?php function test_global_ref() { global $obj; $obj = &new stdclass; } function test_global_noref() { global $obj; $obj = new stdclass; } test_global_ref(); var_dump($obj); test_global_noref(); var_dump($obj); ?>`

A példában szereplő kód végrahajtása a következő kimenetet produkálja:

    NULL
    object(stdClass)(0) {
    }

Hasonló viselkedésmód jellemzi a static utasítást. A referenciák nem statikusan vannak tárolva:

`<?php
function &get_instance_ref() {
static $obj;
echo 'Statikus objektum: ';
var_dump($obj);
if (!isset($obj)) {
// Hozzárendel egy referenciát a statikus változóhoz
$obj = &new stdclass;
}
$obj->property++;
return $obj;
}
function &get_instance_noref() {
static $obj;
echo 'Statikus objektum: ';
var_dump($obj);
if (!isset($obj)) {
// Hozzárendeli az objektumot a statikus változóhoz
$obj = new stdclass;
}
$obj->property++;
return $obj;
}
$obj1 = get_instance_ref();
$still_obj1 = get_instance_ref();
echo "\n";
$obj2 = get_instance_noref();
$still_obj2 = get_instance_noref();
?>`

A példa végrehajtása a következő kimenetet eredményezi:

    Statikus objektum: NULL
    Statikus objektum: NULL

    Statikus objektum: NULL
    Statikus objektum: object(stdClass)(1) {
      ["property"]=>
      int(1)
    }

A példa azt szemlélteti, hogy amikor hozzárendelsz egy referenciát egy statikus változóhoz, az nem lesz megjegyezve amikor újra meghívod a &get_instance_ref() függvényt.

Előző | Tartalom | Következő
Előre definiált változók | Fel | Változó változók