Zasięg zmiennej zależy od miejsca, w jakim ją zdefiniowano. Najczęściej zmienne PHP widoczne są tylko w jednym zasięgu. Taki zasięg obejmuje również pliki dołączone funkcjami include i require. Na przykład:
<?php
$a = 1;
include 'b.inc';
?>
Tutaj zmienna $a będzie dostępna także wewnątrz dołączonego funkcją include pliku b.inc w skrypcie. Jednakże wewnątrz funkcji zdefiniowanych samodzielnie zmienne mają zasięg lokalny. Każda zmienna użyta wewnątrz funkcji jest domyślnie ograniczona do zasięgu lokalnego funkcji. Na przykład:
<?php
$a = 1; /* zasięg globalny */
function test()
{
echo $a; /* odwołanie do zmiennej o zasięgu lokalnym */
}
test();
?>
Ten skrypt nie wyświetli niczego, ponieważ instrukcja echo odwołuje się do zmiennej lokalnej $a, której jak dotąd nie została przypisana żadna wartość. Można tu zauważyć różnicę w stosunku do języka C, gdzie zmienne globalne są zawsze dostępne wewnątrz definicji funkcji, o ile nie zostały nadpisane przez lokalną definicję zmiennej. Może to spowodować problem, że ktoś może nieodwracalnie zmienić wartość zmiennej globalnej. W PHP zmienne globalne muszą być jawnie określone jako globalne wewnątrz funkcji, w której mają być użyte, do czego używamy słowa kluczowego global.
Najpierw, przykład użycia global:
Przykład #1 Używanie polecenia global
<?php
$a = 1;
$b = 2;
function Suma()
{
global $a, $b;
$b = $a + $b;
}
Suma();
echo $b;
?>
Powyższy skrypt wyświetli wynik "3". Przez zadeklarowanie wewnątrz funkcji globalności zmiennych $a i $b, wszystkie odwołania do tych zmiennych będą odnosiły się do ich globalnych wersji. Nie ma żadnych ograniczeń w ilości zmiennych globalnych, na których chcemy operować wewnątrz funkcji.
Drugim sposobem uzyskania dostępu do zmiennych globalnych wewnątrz funkcji jest użycie specjalnej, zdefiniowanej przez PHP tablicy $GLOBALS. Powyższy przykład można zatem przepisać tak:
Przykład #2 Używanie $GLOBALS zamiast polecenia global
<?php
$a = 1;
$b = 2;
function Suma()
{
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}
Suma();
echo $b;
?>
Tablica $GLOBALS jest asocjacyjną tablicą, w której nazwa zmiennej jest kluczem, a zawartość zmiennej wartością komórki tablicy. Zauważ, że $GLOBALS jest dostępna z każdego miejsca, ponieważ $GLOBALS jest tablicą superglobalną. Poniżej przykład demonstrujący moc superglobali:
Przykład #3 Przykład demonstrujący superglobale i zasięg zmiennych
<?php
function test_global()
{
// Większość predefiniowanych zmiennych nie jest "super i wymaga
// 'global', by być dostępnymi w zasięgu lokalnym funkcji.
global $HTTP_POST_VARS;
echo $HTTP_POST_VARS['name'];
// Superglobale są dostępne z każdego miejsca
// i nie wymagają 'global'. Superglobale udostępniono
// wraz z PHP 4.1.0, a HTTP_POST_VARS jest
// uważane za przestarzałe.
echo $_POST['name'];
}
?>
Jeszcze jedną ważną rzeczą, związaną z zasięgiem zmiennych jest zmienna statyczna (ang. static variable). Zmienna statyczna może mieć wyłącznie zasięg lokalny, ale nie traci swojej wartości, kiedy program opuści ten zasięg lokalny, w którym dana zmienna statyczna się znajduje. Rozważmy poniższy przykład:
Przykład #4 Przykład ukazujący przydatność zmiennych statycznych
<?php
function test()
{
$a = 0;
echo $a;
$a++;
}
?>
Ta funkcja jest bezużyteczna, gdyż przy każdym jej wywołaniu zmienna $a otrzymuje wartość 0, w związku z czym funkcja stale wyświetla "0". Występująca potem inkrementacja $a++ nie ma żadnego znaczenia, gdyż funkcja się kończy i zmienna $a znika. Aby powyższa funkcja miała jakiś sens, należy zapobiec gubieniu wartości $a, do czego używamy słowa kluczowego static:
Przykład #5 Przykład użycia zmiennych statycznych
<?php
function Test()
{
static $a = 0;
echo $a;
$a++;
}
?>
Teraz, $a jest inicjowana tylko pry pierwszym wywołaniu funkcji a, przy każdym wywołaniu funkcji test(), zostanie wyświetlona wartość zmiennej $a, po czym ta zmienna zostanie inkrementowana.
Zmienne statyczne pozwalają też na wykorzystanie funkcji rekurencyjnych, czyli takich, które wywołują same siebie. Funkcje rekurencyjne należy pisać ostrożnie, gdyż łatwo jest wywołać nieskończoną rekurencję. Musisz być pewny, że masz odpowiednie mechanizmy do zatrzymania rekurencji w jakimś momencie. Poniższa, prosta funkcja rekurencyjnie liczy do 10, używając zmiennej statycznej $licznik, aby wiedzieć, kiedy się zatrzymać:
Przykład #6 Zmienne statyczne w funkcjach rekurencyjnych
<?php
function test()
{
static $licznik = 0;
$licznik++;
echo $licznik;
if ($licznik < 10) {
test();
}
$licznik--;
}
?>
Informacja:
Zmienne statyczne mogą być deklarowane, tak jak w powyższym przykładzie. Próba przypisania wartości do tego typu zmiennych, poprzez wynik jakiegoś wyrażenia, spowoduje błąd składni (ang. Parse error).
Przykład #7 Deklaracja zmiennych statycznych
<?php
function foo(){
static $int = 0; // prawidłowo
static $int = 1+2; // błąd (w rzeczywistości to jest wyrażenie)
static $int = sqrt(121); // błąd (to również jest wyrażenie)
$int++;
echo $int;
}
?>
Silnik Zend 1 (ang. Zend Engine 1) napędzający PHP4, implementuje modyfikatory statyczny oraz globalny dla zmiennych, pod względem referencji. Na przykład, w rzeczywistości globalna zmienna wprowadzona wewnątrz zasięgu funkcji z wyrażeniem global na dziś dzień tworzy referencję do zmiennej globalnej. Takie zachowanie może prowadzić do nieoczekiwanych sytuacji, czego dowodzi poniższy przykład:
<?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);
?>
Wykonanie tego przykładu da następujące wyniki:
Podobna sytuacja dotyczy deklaracji static. Referencje nie są magazynowane statycznie:
<?php
function &get_instance_ref() {
static $obj;
echo 'Obiekt statyczny: ';
var_dump($obj);
if (!isset($obj)) {
// Przypisanie referencji do zmiennej statycznej.
$obj = &new stdclass;
}
$obj->property++;
return $obj;
}
function &get_instance_noref() {
static $obj;
echo 'Obiekt statyczny: ';
var_dump($obj);
if (!isset($obj)) {
// Przypisanie do obiektu zmiennej statycznej
$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();
?>
Wykonanie tego przykładu da następujące wyniki:
Ten przykład pokazuje, że podczas przypisywania referencji do zmiennej statycznej, nie następuje zapamiętanie, gdy wywołasz funkcję &get_instance_ref() po raz drugi.