Değişken etki alanı

Bir değişkenin etki alanı içinde tanımlandığı bağlamdır. Hemen her PHP değişkeninin sadece tek bir etki alanı vardır. Bu tek etki alanı betiğe include ve require ile dahil edilen dosyalara da uzanır. Örneğin:

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

Burada $a değişkeni içerilen b.inc betiğinin içinde mevcut olacaktır. Fakat, kullanıcı tanımlı işlevlerin etki alanı işleve özeldir. Yani, bir işlev içinde kullanılan herhangi bir değişkenin etki alanı öntanımlı olarak işlevin yerel etki alanı ile sınırlıdır. Örneğin:

<?php
$a 
1/* küresel etki alanı */

function deneme()
{
    echo 
$a/* işlevin etki alanı */
}

deneme();
?>

Bu betik herhangi bir çıktı üretmeyecektir, çünkü echo ifadesi $a değişkeninin yerel sürümüne atıf yapmakta olup bu etki alanı içinde değişkene bir değer atanmamıştır. Bunun C dilinden bir miktar farklı olduğuna dikkat etmiş olabilirsiniz, C dilinde küresel değişkenler, özellikle yerel bir tanımla geçersiz kılınmadıkları sürece, işlevler tarafından özdevinimli olarak erişilebilir olacaktır. Bu bazı sorunlara neden olabilir, öyle ki birileri dikkatsizlikle küresel değişkeni değiştirebilir. PHP'de küresel değişkenler eğer bir işlev içinde kullanılacaksa, o işlev içinde global sözcüğü ile bildirilmeleri gerekir.

global anahtar sözcüğü

İlk olarak, global kullanımına bir örnek verelim:

Örnek 1 - global kullanımı

<?php
$a 
1;
$b 2;

function 
topla()
{
    global 
$a$b;

    
$b $a $b;
}

topla();
echo 
$b;
?>

Yukarıdaki betik 3 çıktısı verecektir. $a ve $b işlev içinde küresel tanımlanarak, her iki değişkene yapılan bütün atıflar küresel sürüme yapılmış olacaktır. Bir işlev tarafından işlenebilecek küresel değişken sayısında bir sınır yoktur.

Küresel etki alanındaki değişkenlere erişimin ikinci yolu PHP tarafından tanımlanmış özel $GLOBALS dizisini kullanmaktır. Önceki örnek şu şekilde yazılabilir:

Örnek 2 - global yerine $GLOBALS kullanımı

<?php
$a 
1;
$b 2;

function 
topla()
{
    
$GLOBALS['b'] = $GLOBALS['a'] + $GLOBALS['b'];
}

topla();
echo 
$b;
?>

$GLOBALS dizisi, anahtarı küresel değişkenin ismi, elemanının değeri değişkenin içeriği olan bir ilişkisel dizidir. $GLOBALS dizisinin her etki alanında mevcut oluşuna dikkat edin, bunun sebebi$GLOBALS dizisinin bir süper küresel olmasıdır. Süper küresellerin gücünü gösteren bir örnek aşağıda verilmiştir:

Örnek 3 - Süper küreselleri ve etki alanlarını gösteren örnek

<?php
function test_global()
{
    
// Çoğu öntanımlı değişken "süper" değildir ve işlev etki
    // alanında geçerli olmak 'global' olmayı gerektirir.
    
global $HTTP_POST_VARS;

    echo 
$HTTP_POST_VARS['isim'];

    
// Süper küreseller her etki alanında geçerlidirler ve
    // 'global' olarak bildirilmeleri gerekmez. Süper küreseller
    // PHP 4.1.0'dan beri mevcutturlar ve HTTP_POST_VARS'ın
    // kullanımı artık önerilmemektedir.
    
echo $_POST['isim'];
}
?>

Bilginize:

Eğer içerildiği dosya bir işlevin içinde içerilmişse global anahtar sözcüğünün işlevlerin dışında kullanımı bir hataya yol açmaz.

Duruk değişkenlerin kullanımı

Değişken etki alanı ile ilgili önemli özelliklerden biri duruk değişkenlerdir. Bir duruk bir değişken sadece işlevin etki alanında geçerli olup, programın çalışması bu etki alanını terkettiği zaman değerini kaybetmez. Aşağıdaki örneğı ele alalım:

Örnek 4 - Duruk değişkenlere ihtiyacı gösteren örnek

<?php
function dene()
{
    
$a 0;
    echo 
$a;
    
$a++;
}
?>

Bu işlev her çağrıldığında $a'yı 0 yapar ve 0 yazdırır, bu nedenle oldukça kullanışsızdır. Değişkeni artıran $a++ bir işe yaramaz çünkü işlev çıktığı gibi $a değişkeni kaybolur. Kaldığı değeri kaybetmeyecek kullanışlı bir sayaç işlevi yapması için $a değişkeni aşağıda static olarak bildirilmiştir.

Örnek 5 - Duruk değişkenlerin kullanım örneği

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

Artık, $a değişkeni sadece dene() işlevinin ilk çağrılışında ilklendirilecek ve işlevin her çağrılışında $a değişkeninin değerini bastıktan sonra değerini bir artıracaktır.

Duruk değişkenler aynı zamanda kendini çağıran işlevlerle çalışmak için de bir yol sunar. Kendini çağıran (recursive) işlev kendi kendini çağırır. Böyle bir işlev dikkatli yazılmazsa sonsuza kadar kendi kendini çağırır. Kendini çağırmayı bir noktada sonlandıracak uygun bir yönteminiz olmalıdır. Aşağıdaki basit işlev, kendini çağırmayı nerede durduracağını bilerek 10'a kadar sayar:

Örnek 6 - Kendini çağıran işlevlerle duruk değişkenler

<?php
function say()
{
    static 
$sayaç 0;

    
$sayaç++;
    echo 
"$sayaç\n";
    if (
$sayaç 10) {
        
say();
    }
    
$sayaç--;
}
say();
?>

Bilginize:

Duruk değişkenler yukarıdaki örneklerde yapıldığı gibi tanımlanabilir. PHP 5.6 itibariyle, bu değişkenlere ifadelerin sonuçlarını değer olarak atayabilirsiniz fakat burada herhangi bir işlev kullanamazsınız, bu bir çözümleme hatasına sebep olur.

Örnek 7 - Duruk değişken bildirimi

<?php
function foo(){
    static 
$int 0;          // doğru
    
static $int 1+2;        // doğru  (PHP 5.6 itibariyle)
    
static $int sqrt(121);  // yanlış (bir işlevle atandığı için)

    
$int++;
    echo 
$int;
}
?>

Bilginize:

Duruk bildirimler derleme sırasında çözümlenir.

global ve static değişkenlere gönderim

PHP 4'ün işletmeni olan Zend Motoru 1, static ve global değişken niteleyicilerini gönderim olarak gerçeklemiştir. Örneğin, global deyimi ile bir işlevin etki alanında geçerli kılınan bir küresel değişken aslında kendine bir gönderim oluşturur. Bu durum aşağıdaki örnekte de görüldüğü gibi beklenmedik davranışlara yol açabilir:

<?php
function gönderimli_küresel_dene() {
    global 
$nesne;
    
$nesne = &new stdclass;
}

function 
gönderimsiz_küresel_dene() {
    global 
$nesne;
    
$nesne = new stdclass;
}

gönderimli_küresel_dene();
var_dump($nesne);
gönderimsiz_küresel_dene();
var_dump($nesne);
?>

Yukarıdaki örneğin çıktısı:


NULL
object(stdClass)#1 (0) {
}

Aynı davranış static deyimine de uyar. Gönderimler duruk olarak saklanmazlar:

<?php
function &gönderimli_örnek() {
    static 
$obj;

    echo 
'Duruk nesne: ';
    
var_dump($obj);
    if (!isset(
$obj)) {
        
// Duruk değişkene gönderim atayalım
        
$obj = &new stdclass;
    }
    
$obj->property++;
    return 
$obj;
}

function &
gönderimsiz_örnek() {
    static 
$obj;

    echo 
'Duruk nesne: ';
    
var_dump($obj);
    if (!isset(
$obj)) {
        
// Duruk değişkene nesne atayalım
        
$obj = new stdclass;
    }
    
$obj->property++;
    return 
$obj;
}

$nesne1 gönderimli_örnek();
$bu_da_nesne1 gönderimli_örnek();
echo 
"\n";
$nesne2 gönderimsiz_örnek();
$bu_da_nesne2 gönderimsiz_örnek();
?>

Yukarıdaki örneğin çıktısı:


Duruk nesne: NULL
Duruk nesne: NULL

Duruk nesne: NULL
Duruk nesne: object(stdClass)#3 (1) {
["property"]=>
int(1)
}

Bu örnek, bir duruk değişkene gönderimli atama yapılması halinde, &gönderimli_örnek() işlevi ikinci kez çağrıldığında değişkene atanan değerin saklanmadığını gösterir.