İstinad dəyişənləri

Proqramlaşdırmada göstərici dəyişən pointer (İngilis dilində “pointer“, Rus dilində “указатель“) anlayışı var (məsələn, C və Paskal dilində). Bu dəyişəndə kompüterin yaddaşının xanalarının adresini saxlamaq mümkündür, yəni bu dəyişən yaddaşda hər hansı bir qiymətin yerini “göstərir”. İlk görünüşdə mürəkkəb görünsə də əslində bu anlayışı kitab misalında aydın təsəvvür etmək mükündür. Kitabın mündəricatındakı sətirləri uyğun bölmələrin kitabda yerini göstərən “göstəriciləri” kimi qəbul etmək olar. Belə göstəricinin qiyməti dedikdə isə kitabın vərəqlənərək göstəricinin göstərdiyi uyğun səhifəsinin oxunması başa düşülür.

Göstərici dəyişənlər sətirlər, massiv və asosiativ massivlər (lookup table), ağac strukturu üzərində təkrarlanan əməliyyatları nəzərə çarpacaq dərəcədə tezləşdirir.

PHP-də ümumilikdə pointer anlayışı yoxdur, ancaq burda digər dəyişənlərə “istinad edən” dəyişən yaratmaq mümkündür (İngilis dilində “reference variable“, Rus dilində “ссылочные переменные“). İstinad dəyişənlərinin üç növü müvcuddur: birbaşa, simvolik və obyektlərə istinad.

Birbaşa istinad

Birbaşa istinad dedikdə başqa bir dəyişənin sinonimi başa düşülür. Çox səviyyəli istinad, yəni istinad dəyişəninin özünə istinad yaratmaq qəbul edilmir. Buna görə də birbaşa istinad dəyişənlərini sinonimdən başqa qeyri-adi bir anlayış kimi qəbul etmək lazım deyil.

Birbaşa istinad yaratmaq üçün =& operatorundan istifadə edilir. Nümunə:

$a = 10;
$b =& $a; // artıq $b dəyişəni $a dəyişəni ilə eyni mənalıdır
$b = 0; // deməli həm də $a = 0 olur
echo "b = $b, a = $a"; // "b = 0, a = 0" çap edilir

Həmçinin massivin elementlərinə də istinad dəyişəni yaratmaq olar və bununla birbaşa istinad dəyişənləri simvolik növdən fərqlənir. Nümunə:

$h = array(
  'ad' => 'Cəfər',
  'soyad' => 'Cabbarlı'
);
$r =& $h['ad']; // $r - 'ad' indeksli elementlə eyni mənalı olur
$r = "Abbas"; // əslində $h['ad'] = "Abbas";
echo $h['ad']; // "Abbas" çap edilir

Digər bir tərəfdən, birbaşa istinad yaradılacaq massivin indeksi mövcud olmaya da bilər:

<?php
  $h = array(
    'ad' => 'Cəfər',
    'soyad' => 'Cabbarlı'
  );
  $b =& $h['ata_adı']; // $b - 'ata_adı' indeksli elementlə eyni mənalı olur
  echo "'ata_adı' indeksli element: " . $h['ata_adı'] . "<br/>";
  echo "'ata_adı' indeksli mövcud olmayan elementin tipi: " . gettype($h['ata_adı']); 
?>

$b dəyişəninə heç nə mənimsədilməməsinə baxmayaraq proqramın yerinə yetirliməsi zamanı $h massivində ‘ata_adı’ indeksi element yaradılmış olur və onun qiyməti null olur və onu çap edəndə heç bir xəbərdarlıq göstərilmir, NULL çap edilir. Burdan çıxır ki, birbaşa istinad mövcud olmayan “obyektə” edilə bilməz və belə hal baş verərsə uyğun obyekt yaradılmış olur.

Maraq üçün proqramın kodunda istinad yaradılan sətri silin. Bu zaman mütləq $h massivində ‘ata_adı’ indeksli elementin mövcud olmadığı haqda məlumat çap ediləcək.

Yaddaşın təmizlənməsi alqoritmi

Gəlin PHP-də dəyişənlərin işləmə prinsipini aşağıdakı kimi təsəvvür edək. $a dəyişəninə hər hansı dəyər mənimsədilən zaman nə baş verir?

  1. Dəyərin yadda saxlanılması üçün əməli yaddaşda yer ayrılır.
  2. PHP öz daxili cədvəllərində yeni yaradılmış $a dəyişənini qeyd edir və bu dəyişəni əməli yaddaşda indicə ayrılmış yaddaş sahəsi ilə əlaqələndirir.

Artq, $a-ya müraciət zamanı PHP onu öz cədvəllərində tapıb onun qiymətini əldə etmək üçün əvvəldən ayrılmış yaddaş bölməsinə müraciət edəcək.

$a dəyişəninə birbaşa $r istinadı yaradılan zaman nə baş verdiyinə baxaq. Bu zaman PHP öz daxili cədvəllərində $r dəyişəni haqqında yeni qeyd yaradır, ancaq bu dəfə onunla yaddaşın yeni sahəsini yox $a dəyişəninə ayrılmış sahəni əlaqələndirir. Nəticədə $a$r yaddaşın eyni bölməsinə yönəlmiş olur və buna görə də bu dəyişənlər sinonim olurlar.

PHP-in birbaşa istinad üçün yerinə yetirdiyi unset($r) operatoru onun istinad etdiyi obyekti yaddaşdan silmir və onun aid olduğu yaddaş sahəsini təmizləmir. O, yalnız istinad dəyişənilə “obyekt” arasındakı əlaqəni ləğv edib öz daxili cədvəllərindən $r haqqında məlumatı silir. Əslində bu zaman o, “obyektin” özünü yox edə bilməz, çünki $a dəyişəni hələ də bu obyektə yönəlmiş olaraq qalır.

Beləliklə, birbaşa istinad və və onun istinad etdiyi dəyişənin özü (obyekt) tamamilə eynihüquqludur. Onlardan birinin dəyişməsi digərində də həmin dəyişikliyə səbəb olur. unset() operatoru obyektlə istinad arasında əlaqəni ləğv edir. Obyektin özü isə yalnız, ona heç bir istinadın olmadığı andan, yəni onunla əlaqəli artıq heç bir dəyişənin qalmadığı andan sonra yaddaşdan silinir.

Belə alqoritm, yəni obyektlərin onlara sonuncu istinadın yox olmasından sonra silinməsinə, adətən yaddaşın təmizlənməsi alqoritmi deyilir (Rus dilində “алгоритм сбора мусора“, İngilis dilində “garbage collection“).

Simvolik istinad

Simvolik istinad digər dəyişənin adını saxlayan sətir tipli dəyişəndir. Simvolik istinadı yaradılmış dəyişənin qiymətini əldə etmək üçün istinad dəyişəninin solunda əlavə $ işarəsi yazmaq lazımdır. Nümunə:

$right = "red";
$wrong = "blue";
$color = "right";
echo $$color;      // $right dəyişəninin qiymətini çap edir ("red")
$$color = "white"; // $right dəyişəninə yeni qiymət mənimsədir

Göründüyü kimi adi sətir dəyişənindən istinad kimi istifadə etmək üçün onun soluna $ işarəsi yazılıb. Belə yazılış interpretatora $color dəyişəninin özünün qiymətini yox, adı $color dəyişəninin qiymətinə uyğun dəyişənin qiymətini götürməyi bildirir.

Praktikada bu tip istinad çox nadir hallarda istifadə olunur və ondan istifadə proqramı başa düşmək üçün daha da mürəkkəbləşdirir. Buna görə də onların istifadəsindən qaçmaq məsləhətdir.

UNIX ƏS-in fayl sistemi ilə yaxından tanış olanlara “birbaşa” və “simvolik” istinad anlayışları fayllarla eyni adlı anlayışları xatırlada bilər. Burda demək olar ki, tam analogiya var və PHP haqqında rəsmi mənbələrdə də bu xüsusiyyətə diqqət yetirilir.

Obyektə istinad

PHP 5 versiyasından başlayaraq massiv və obyektlərin nüsxələnməsi, yəni digər bir dəyişənə mənimsədilməsi “istinad” vasitəsilə edilir. Bir qədər irəli gedərək, obyektin yaradılması nümunəsinə baxaq:

<?php
  // Yeni klass elan edək
  class AgentSmith {} 
  // AgentSmith klassına uyğun obyekt yaradılır
  $first = new AgentSmith();
  // klassın atributuna qiymət mənimsədirik
  $first->mind = 0.123;
  // Obyektin nüsxəsini yaradırıq
  $second = $first;
  // Yeni nüsxədə "mind" atribununun qiymətini dəyişirik
  $second->mind = 100;
  // Hər iki obyektin atributunu çap edirik
  echo "First mind: {$first->mind}, second: {$second->mind}";
?>

Skripti işə salsaq görərik ki, çap olunun rəqəmlər eynidir və ikisi də 100-ə bərabərdir. Bunun səbəbini izah edək. İş orasındadır ki, PHP-də dəyişəndə obyektin özü saxlanılmır. Dəyişəndə yalnız uyğun obyektə istinad saxlanılır. Proqramın sonunda echo $first; yazıb işə salsaq “Object id #1” çap edildiyini görərik (bu zaman həm də obyektin birbaşa sətrə çevirilməsinin mümkün olmaması haqqında xəbərdarlıq çap ediləcək). Bu, dəyişənin 1 nömrəli obyektə istinad olduğunu göstərir. Dəyişənlərin ikisi də eyni obyektə istinad etdiklərindən, $second dəyişəninin də qiymətini çap etmək istəyəndə eyni məlumat çap ediləcək.

Göründüyü kimi, dəyişənlərdə yalnız obyektə istinad saxlanıldığından onların digər dəyişənlərə mənimsədilməsi zamanı obyektin özü yox, məhz ona istinad mənimsədilmiş olur. Bunu əslidə sadə bir bənzətmə ilə daha aydın təsəvvür etmək olar: Hər hansı tədbirə gedərkən paltonu (obyekt) qarderoba təhfil verib ona uyğun nömrə (istinad) götürürük. Sonra usta yanına gedib bu nömrənin dublikatını hazırladırıq. Nəticədə bir paltoya iki nömrə əldə etmiş olacağıq, palto isə bir nüsxədə olaraq qalacaq.

Gələcəkdə obyektlər və onlara istinadlar barəsində ətrafalı danışılacaq.

One thought on “İstinad dəyişənləri”

Leave a Reply