Vue CLI-də şəklin istifadəçi tərəfdə ölçüsünün dəyişdirilməsi

Adətən serverə şəkil yükləmək üçün istifadə olunan formalarda, xüsusən də mobil qurğu istifadəçilərinin qarşılaşdığı bir çətinlik var. Məsələn, telefonla şəkli çəkib forma vasitəsilə serverə göndərəndə şəklin ölçüsü serverin konfiqurasiyasında qeyd edilmiş maksimal post həcmini aşır. Nəticədə faylı emal edəcək proqrama şəkil çatmır və istifadəçiyə "Fayl yüklənmədi" məlumatı çıxarılır.

Bu məsələnin bir neçə həll üsulu var. Ən rahat ancaq hər dəfə tətbiq edilə bilinməyən üsul maksimal post həcmini artırmaqdır. Bu üsul həmişə düzgün həll deyil. Belə ki, çox vaxt şəklin həcminin o qədər böyük olması həm serverin yaddaşında yer həm də emal müddəti baxımından sərf etmir, həm də adətən çox keyfiyyətli şəklə də ehtiyac olmur.

Digər həll hal-hazırda HTML5-in imkanı vasitəsilə şəklin istifadəçi tərəfdə ölçüsünün dəyişdirilməsi, keyfiyyətinin azaldılmasıdır.

Vue CLI vasitəsilə deyilən sonuncu üsulun həllini aşağıdakı kimi etmək mümkündür.

Bu həll məhz Vue CLI-dən asılı deyil və asanlıqla ad JavaScript-ə çevirilib məsələn JQuery vasitəsilə də istifadə edilə bilər. Funksiyaya mütləq parametr olaraq HTML file input-un dəyəri ötürülməlidir.

PHP-də fevral problemi

Üzərində işlədiyimiz proyektlərin birində PHP vasitəsilə istifadəçinin hər ay etdiyi ödənişlərini verilmiş aralıqda təqvim formasında çıxartmalı idik. Ödənişlər haqqında xüsusi servisdən əldə edilən məlumatlarda yalnız istifadəçinin ödəniş etdiyi ay və məbləğ qaytarılırdı. Yəni məsələn, bir yanvar ayında və bir də aprel ayında ödəniş edilibsə, servisdən ancaq iki – yanvar və aprel – ayı haqqında məlumat qaytarılırdı.

Təqvimi göstərmək üçün əvvəlcə gərək verilmiş aralıqda ardıcıl olaraq ilin ayları müəyyən edilsin, sonra həmən aylar servisdən gələn məlumatla tutuşdurulub ödəniş varsa həmən ayda edilmiş ödəniş, yoxdursa 0 çap edilsin.

Beləliklə, istifadəçi proqramda başlanğıc və son ayları daxil edir. Qurulmuş məntiqə görə skript dövrü işə salır, başlanğıc ayın üzərinə hər dəfə bir ay gələrək alınan nəticənin sonuncu aya bərabər olub olmadığını yoxlayır və beləliklə aylar ardıcıllığını əldə etmiş olur.

Hər şey hazırlanıb iş təhfil veriləndən sonra maraqlı hallar baş verməyə başladı. Belə ki, php skript hərdən işini bitirə bilmir və verilmiş taymautdan sonra işini bitirməmiş dayandırılırdı. Skripti tələsik, sadə debaq etdikdən sonra məlum oldu ki, proqram sonsuz dövrə düşür və nəticədə PHP-də tarixlərlə işləyən standart funksiyalarda xəbərimiz olmayan bug aşkar etmiş olduq.

Növbəti aylar PHP-in strtotime funksiyasına başlanğıc ay string formasında və yanına +n month yazısı əlavə etməklə müəyyən edilir. Məsələn: strtotime("2018-05-10 +1 month") verilmiş tarixdən bir ay sonrakı təqvim gününü timestamp formasında qaytarmalıdır. Verilmiş başlanğıc ayından sonra 20 ayı çap edən skript aşağıdakı kimidir:

$begin_month = 1;
$begin_day = 10;
$begin_year = 2018;

$date_string = date("Y-m-d", mktime(0, 0, 0, $begin_month, $begin_day, $begin_year));
for ($i = 1; $i < 20; ++$i) {
    $next_month = date("m/Y", strtotime($date_string . " +" . $i . " month"));
    print $next_month . '<br>';
}

Nəticə gözəldir:

02/2018
03/2018
04/2018
05/2018
06/2018
07/2018
08/2018
09/2018
10/2018
11/2018
12/2018
01/2019
02/2019
03/2019
04/2019
05/2019
06/2019
07/2019
08/2019

Amma başlanğıc tarixdə $begin_month = 12; $begin_day = 31; $begin_year = 2018; kimi nəzərə alsaq nəticə çox gözlənilməz olur:

01/2019
03/2019
03/2019
05/2019
05/2019
07/2019
07/2019
08/2019
10/2019
10/2019
12/2019
12/2019
01/2020
03/2020
03/2020
05/2020
05/2020
07/2020
07/2020

Göründüyü kimi, strtotime funksiyası +n month əlavəsi ilə özünü normal aparmır. Proqramlaşdırma zamanı bu xətanı müəyyən etdiyimizdən və bir az araşdırmalardan sonra tarixi PHP-in standart DateTime obyekti ilə hesablamağa qərar vermişdik:

$begin_month = 1;
$begin_day = 10;
$begin_year = 2018;

$mk_date = date('U', mktime(0, 0, 0, $begin_month, $begin_day, $begin_year));

$date = new \DateTime('@' . $mk_date);
for ($i = 1; $i < 20; ++$i) {
    $date->modify('+1 month');
    print $date->format('m/Y') . '<br>';
}

Nəticə:

02/2018
03/2018
04/2018
05/2018
06/2018
07/2018
08/2018
09/2018
10/2018
11/2018
12/2018
01/2019
02/2019
03/2019
04/2019
05/2019
06/2019
07/2019
08/2019

Gözəldir, hər şey işləyir və testlərdən sonra proqramı bu formada işə buraxmışdıq. Ancaq, sonradan məlum oldu ki, məsələn başlanğıc tarixdə $begin_month = 12; $begin_day = 31; $begin_year = 2018; kimi nəzərə alsaq nəticə yenə də gözlənilməz olur:

01/2019
03/2019
04/2019
05/2019
06/2019
07/2019
08/2019
09/2019
10/2019
11/2019
12/2019
01/2020
02/2020
03/2020
04/2020
05/2020
06/2020
07/2020
08/2020

Göründüyü kimi, verilən məsələdə DateTime obyekti özünü strtotime funksiyasına nisbətən normal aparsa da, hazırki nümunədə vefral ayı çap edilməyib. İstifadəçi də təsadüfən fevral ayına qədər nəticəni görmək istədiyəndə proqram fevral ayını nəzərə almadığına görə sonsuz dövr alınır.

Nisbətən uzun araşdırmalardan və testlərdən sonra normal nəticəni DateTime obyektinin modify metoduna 'last day of next month' parametrini ötürməklə ala bildik:

$begin_month = 12;
$begin_day = 31;
$begin_year = 2018;

$mk_date = date('U', mktime(0, 0, 0, $begin_month, $begin_day, $begin_year));

$date = new \DateTime('@' . $mk_date);
for ($i = 1; $i < 20; ++$i) {
    $date->modify('last day of next month');
    print $date->format('m/Y') . '<br>';
}

Nəticə gözəldir və uzun testlərdən sonra həqiqətən də normal işlədiyinə əmin olduq:

01/2019
02/2019
03/2019
04/2019
05/2019
06/2019
07/2019
08/2019
09/2019
10/2019
11/2019
12/2019
01/2020
02/2020
03/2020
04/2020
05/2020
06/2020
07/2020

Göründüyü kimi, PHP-nin imkanlarını əzbər bilsək də qurduğumuz məntiqin düzgünlüyünə əmin olmağımız hələ proqramın düzgün nəticə verəcəyinə 100% dəlalət etmir. PHP-in rəsmi saytında komentlərdə bu bug barəsində az-çox məlumat da var.

Sizin də rast gəldiyiniz belə bug-lar varsa komentə yazın.

Sətr ifadələri

PHP-də sətrlər əsas obyektlərdən biridir. Əvvəlki mövzularda qeyd edildiyi kimi, sətrlərdə formatlaşdırma simvolları ilə birlikdə mətn və hətta ikilik sistemdə verilənləri saxlamaq mümkündür. Cüt dırnaq və ya apastrof arasında təyin edilmiş sətrlər sintaktik cəhətdən doğru olaraq bir sətrdə başlayıb digər sətrdə bitə bilər:

$multiline = "Bu mətn bir sətrdə başlayır,
ikinci sətrdə,
üçüncü sətrdə davam edir və s.";

Əvvəki mövzularda biz nümunələrdə cüt dırnaq və ya apastrof arasında təsfir edilmiş sətr sabitlərindən istifadə etmişdik. Onlar arasında fərqi izah edək.

Apastrofa alınmış sətr

Əgər sətr apastrof arasında yazılıbsa (məsələn, 'sətr') o, hərfi mənada, yazıldığı kimi qəbul edilir. Sətr daxilində iki halda xüsusi iki işarə ardıcıllığı bu qaydadan kənara çıxır:

' ardıcıllığı PHP tərəfindən apastrof işarələri arasında yazılmış sətr daxilində bir apastrof işarəsi çapı kimi başa düşülür: 'apastrof ' kimi yazılır';
\ ardıcıllığı bir tərsinə bölmə – tərsinə sleş – işarəsi kimi başa düşülür və sətrin daxilində bu işarəni çap etməyə imkan verir: 'C:\my_file.txt'.

Digər başqa simvollar məhz özlərini işarə edirlər və xüsusi hal olaraq qeyd etmək lazımdır ki, $ işarəsinin bu halda heç bir xüsusi mənası olmur. Bu, həmçinin o deməkdir ki, apastrof işarələri daxilində yazılmış sətrlərdə qeyd edilmiş dəyişənlərin identifikatorları interpolyasiya edilmir, yəni onlar qiymətləri ilə əvəz edilmirlər.

Dırnaq arasında sətr

Apastrofla müqayisədə dırnaq işarələri daha “liberaldır”. Belə ki, dırnaq işarələri arasında yazıldıqda bu və ya digər xüsusi simvolu işarə edən xüsusi metasimvollar ardıcıllıqlarının sayı daha çoxdur. Aşağıda onlardan bir neçəsi göstərilib:

n yeni sətr işarəsidir;
r karterin geri qaytarılması işarəsi;
t tabulyasiya simvolu;
$ xüsusi $ işarəsini təsfir edir. Bu halda $ işarəsindən sonra gələn yazı dəyişən kimi interpolyasiya edilmir;
" dırnaq işarəsini göstərir;
\ bir tərsinə sleş işarəsini göstərir;
xNN onaltılıq sistemdə kodu NN olan işarəni göstərir.

Sətrlərin daxilində dəyişənlər interpolyasiya edilirlər. Məsələn:

$hi = "Hello";
echo "$hi world!";

Bu fraqment aşağıdakı yazını çap edir:

Hello world!

yəni, sətrin daxilində $hi yazısı məhz $hi dəyişəninin qiyməti ilə əvəz edildi. Buna səbəb istənilən dəyişənin qarşısında yazılmış dollar işarəsidir.

Başqa nümunəyə baxaq:

$SOME = "Hell"; // sonunda "o" hərfi yazılmamış "Hello" sözü
echo "$SOMEo world!";

Biz bu halda da nəticəni əvvəlki nümumənin nəticəsi kimi gözləyə bilərik, ancaq bu halda PHP $SOME və ya $SOMEo dəyişənindən məhz hansının nəzərdə tutdulduğunu müəyyən edə bilməyəcək. Bu fraqmenti işə salsaq PHP $SOMEo dəyişəninin müəyyən edilmədiyi haqda məlumat çap edəcək. İstədiyimiz nəticəni əldə etmək üçün nümunə aşağıdakı kimi yazılmalıdır:

$SOME = "Hell"; // sonunda "o" hərfi yazılmamış "Hello" sözü
echo $SOME."o world!"; // bir üsul
echo "{$SOME}o world!"; // növbəti üsul
echo "${SOME}o world!"; // üçüncü üsul

Göründüyü kimi, bu problemi dəf etməyin üç üsulu mövcuddur. İstəkdən asılı olaraq istənilən bir variantı istifadə etmək olar. Ən perspektiv variant kimi isə {$SOME} yazılışını göstərmək lazımdır. Çünki, bu üsulla sətr daxilində dəyişənlərin qiymətləri ilə yanaşı, həmçinin, massiv elementləri və obyektlərin parametrlərini də göstərmək mümkündür:

$action = array(
	"left" => "survive",
	"right" => "kill'em all"
); 
echo "Seçilmiş element: {$action['left']}";

{} konstruksiyası daxilində massivin açar sözünü göstərmək üçün istifadə edilən apastroflara fikir vermək lazımdır. Onlar yazılmasa interpertator xəbərdarlıq göstərəcək. Fiqurlu mötərizələrsiz və apastrofsuz yazılarsa:

echo "Seçilmiş element: $action[left]";

xəbərdarlıq göstərilməyəcək və əvvəlki nümunə ilə eyni sətr çap ediləcək.

Məntiqi ifadələr

PHP-də istənilən ifadə öz “məntiqi” mənasında məntiqi ifadə hesab edilə bilər. Belə ki, əvvəlki mövzularda qeyd edildiyi kimi məntiqi doğru rolunu istənilən sıfırdan fərqli rəqəm, sıfırla nəticələnməyən ifadə, boş olmayan yazı və s. ifadələr, məntiqi yanlış rolunu isə digər ifadələr oynaya bilər

Məntiq dəyişənləri haqqında danışılarkən qeyd edilmiş bütün xüsusiyyətlər məntiqi ifadələr üçün də doğrudur. Məntiqi ifadələr çox vaxt >, <== (bərabərlik), || (məntiqi VƏ YA), && (məntiqi VƏ), ! (məntiqi İNKAR) və s. operatorların istifadəsilə yaranır. Məsələn:

$less = 10 < 5;// $less - yalan $equals = $b == 1;// $equals - $b == 1 olarsa doğru, $between = $b >= 1 && $b <= 10;// $between - $b 1-dən 10-a qədər (10 daxil olmaqla) olarsa doğru
$x = !($b || $c) && $d;// $b və $c yalan, а $d - doğru olarsa true

Bu və ya digər məntiq dəyişəninin doğruluğu elə istənilən məntiqi ifadələrin yoxlanılması kimi eyni üsulla yerinə yetirilir:

$between = $x >= 1 && $x <= 7; // $between -ə ifadənin qiymətini mənimsədirik
if ($between) echo "x lazımi aralıqdadır";

İfadələr və əməliyyatlar

Əvvəlki mövzularda proqramın əməliyyat etdiyi dəyişənlər, onların tiplərinə ətraflı nəzər yetirildi. Bu bölmədə PHP proqramlaşdırma dilinin əsas imkanları haqqında danışılacaq.

İfadələr

Ümumi baxsaq, ifadələr PHP-in üzərində dayandığı sütunlardan biridir. Praktik olaraq proqramda nə yazılırsa hamısı ifadədir. İfadə dedikdə müəyyən mənaya malik “nəsə” başa düşülür. Bunun əksi də düzgündür. Əgər nəsə müəyyən mənaya malikdirsə bu elə ifadədir.

İfadəyə ən sadə misal olaraq mənimsətmə operatorunun sağ tərəfində dayanan dəyişən və ya sabiti göstərmək olar. Məsələn: $a = 5; operatorunda 5 rəqəmi ifadədir, çünki o, 5 qiymətinə malikdir. Belə mənimsətmədən sonra biz haqlı olaraq deyə bilərik ki, $a 5-dir. Bundan sonra $b = $a; yazsaq aydındır ki, $b də 5 olacaq, çünki operatorun sağında yerləşmiş $a 5 qiymətinə malikdir.

Əvvəldə yazdığımız kimi, praktiki olaraq proqramı tərtib etdiyimiz hər şey ifadədir və $b = $a yazısı da həmçinin ifadədir. Bu ifadənin qiymətini asanlıqla təxmin etmək olar: 5. Bu isə o deməkdir ki, aşağıdakı kimi əmrlər də yazmaq olar:

$a = ($b = 10);   // və ya sadəcə $a = $b = 10

Bu zaman $a$b dəyişənlərinə 10 qiyməti mənimsədiləcək. Daha mürəkkəb, trivial görsənməyən misala baxaq:

$a = 3 * sin($b = $c + 10) + $d

Bu əmrlərin yerinə yetirilməsindən sonra dəyişənin qiyməti aşağıdakı sətirlərin yerinə yetirilməsi ilə eyni hüquqlu olacaq:

$b = $c + 10;
$a = 3 * sin($c + 10) + $d;

Göründüyü kimi, PHP-də mürəkkəb ifadənin hesablanması zamanı onun müəyyən hissəsi növbəti sətrlərdə lazım olacaqsa, o hissəni dəyişənlə göstərmək olar. Bu üsul işi çox rahatlaşdıra, proqramın kodunu xeyli qısalda bilər. Bu zaman kodun oxunaqlığı əvvəlki səviyyədə qalır. Buna görə də bu üsuldan lazım olduqca istifadə etmək məsləhətdir.

Qeyd etmək lazımdır ki, hər bir ifadənin qiymətinin özünün tipi var. Məsələn:

$a = 10 * 20; 
$b = "" . (10 * 20); 
echo "$a:".gettype($a).", $b:".gettype($b); // "200:integer, 200:string" çap olunacaq

Photoshop-un süni intellektlə işləyən yeni versiyası

23 yanvarda Adobe şirkəti şəkillərlə işləyən məşhur Photoshop proqramının yeni versiyasını — Photoshop 19.1 versiyasını — buraxıb.

Yeni imkanlar

Yeni versiyada altı əsas yenilik var:

  1. Select Subject — süni intellektin köməyi ilə uyğun bölmələrin seçilməsi, ayrılması:
  2. Windows 10 Creator’s Edition-un 100%-dən 400%-dək miqyası dəyişdirilməsi və istənilən dioqonallı monitorlarda interfeysin optimizasiyası ilə yüksək sıxlıqlı ekranların dəstəklənməsi.
  3. Şəkildə rənglərin neytrallaşdırılması idarə etmək imkanına malik təkmilləşdirilmiş Select və Mask alətləri:
  4. Adobe XD-də SVG daha geniş dəstəklənir
  5. Microsoft Surface Dial-ın Technology Preview-dan ayrılması və daha çox imkanlarının olması:
  6. HEX, RGB, HSB rəng modelləri arasında keçid sürətlənib:

Daha geniş məlumat və yükləmək üçün link Adobe-un öz saytında yerləşdirilib.

Neyron şəbəkəsinə saytın dizaynını şəkildən HTML koda çevirməyi öyrətdilər

FloydHub-un tədqiqatçıları koder-neyroşəbəkə yarada biliblər.

2017-ci ilin may ayında maşın öyrənməsinin köməyi ilə qrafik istifadəçi interfeyslərini şəkildən avtomatik generasiya edə bilən proqram – –pix2code təqdim edilmişdi. Bunun alqoritmi əsasında FloydHub-un əməkdaşları HTML şablonları adi şəkillərdən birbaşa koda çevirə bilən öz neyro şəbəkələrini yaratmaq qərarına gəliblər.

Nəticədə əldə edilmiş proqrama arzu olunan dizaynın şəklini ötürmək olur.

Neyroşəbəkə şəkli HTML-ə çevirir.

The neural network converts the image into HTML markup

Hazır maket generasiya olunur.

Rendered output

Belə nəticəni əldə etmək üçün proqramın öyrədilməsi zamanı modelə şəkillərlə yanaşı onlara uyğun HTML teqlərini də ötürüblər. Ötürülən məlumatları analiz edərək alqoritm asılılıqları müəyyən edir və lazım olan HTML konstruksiyaları təxmin etməyi öyrənir. Əvvəldən öyrədilmiş, şərti “şəkil – teqlər çoxluğu” asılılığından dataset formalaşır və bu məlumatlar gələcəkdə şəbəkəyə yeni məlumatlara uyğun düzgün istiqamət seçməyə kömək edir.

Nəticədə təcrübədə müəyyən edilib ki, əldə edilən neyroşəbəkə sadə şablon maketi təqribən 550 iterasiyaya koda çevirə bilir.

Üç il ərzində maşın öyrənməsi frontenddə işləmək təsəvvürünü tamamilə dəyişəcək. O, prototipin yaradılma sürətini artıracaq və proqram təminatının hazırlanması baryerini aşağı salacaq.

Emil Wallner, kodlaşdıran alqoritmin yaradıcısı

Sabitlər

Proqrmalaşdırma zamanı elə parametrlər olur ki, proqramın yerinə yetirilməsi zamanı onların qiyməti dəyişmir. Bu, riyaziyyata aid sabit ədədlər, direktoriyanın, faylın yerləşdiyi yerin yolu, parollar və s. ola bilər. Məhz belə məqsədlər üçün PHP-də xüsusi konstruksiya, sabitlər nəzərdə tutulub (ing:constant“, rus: константа).

Sabitlərin dəyişəndən fərqi ondadır ki, sabitlərə dəyəri proqramın yerinə yetirilməsi zamanı yalnız bir dəfə mənimsətmək olar və onların identifikatorlarının qarşısında $ işarəsi yazılmır. Məsələn:

// Qəbul edək ki, əvvəldən PI sabiti 3.1416... kimi təyin edilib
$a = 2.34 * sin(3 * PI / 8) + 5;
// использование константы
echo "Bu PI ədədidir";
// "Bu PI ədədidir" çap olunacaq
echo "Bu ". PI . " ədədidir";
// "Bu 3.1416... ədədidir" çap olunacaq

Əslində, sabitlərin adının solunda “dollar” işarəsinin yazılmaması bir tərəfdən rahatlıqdır. Digər tərəfdən isə göründüyü kimi, bu həm də çatışmamazlıqdır, artıq sabitləri yazı sətrinin daxilində birbaşa istifadə edə bilmirik. Sabitlərin adları reqistrə həssasdır və buna görə də məsələn, PIpi sabitləri tam fərqli iki sabitlərdir.

PHP-də interpretatorun özü tərəfindən elan edilmiş sabitlər və proqramçı tətəfindən təyin edilən sabitlər var.

Elan edilmiş sabitlər

PHP-də interpretatorun özü tərəfindən elan edilmiş bir neçə sabitlər var.

  • __FILE__  – hal hazırda yerinə yetirilən proqramın yerləşdiyi faylın adını saxlayır
  • __LINE__ – interpretatorun hal hazırda yerinə yetirdiyi komandanın yerləşdiyi sətrin sıra nömrəsi. Bu, proqramın yerinə yetirilməsi zamanı hər dəfə dəyişən, özünəməxsus sabitdir. (Həmçinin, idarəetməni digər fayla ötürəndə __FILE__ sabiti də dəyişir)
  • __FUNCTION__ – işə salınmış cari funksiyanın adı
  • __CLASS__ – cari klassın adı
  • PHP_VERSION – PHP interpretatorun versiyası
  • PHP_OS – hal-hazırda PHP-in işlədiyi ƏS-in adı
  • PHP_OS – hal-hazırda PHP-in işlədiyi ƏS-ə uyğun sətrin sonunu bildirən simvol: Linux-da n, Windows-da rn, Mac OS X-də nr kimi müəyyən olunur.
  • true və ya TRUE – bu sabit məntiqi “doğru” dəyərini saxlayır
  • false və ya FALSE – məntiqi “yanlış” dəyərini saxlayır
  • null və ya NULLnull dəyərini saxlayır

Qeyd edək ki, true, falsenull sabitlərinin böyük hərflərlə də  – TRUE, FALSENULL kimi yazılmasına icazə verilir. Ancaq, gələcəkdə baxacağımız PSR-2 standartı bunların kiçik hərflərlə yazılmasını tələb edir.

Sabitlərin təyin edilməsi

PHP-də özümüzün, xüsusi sabitlərini yaratmaq üçün define() konstruksiyasından istifadə edilir və bu konstruksiya aşağıdakı kimi təyin edilib:

void define(string $name, string $value, bool $case_sen = true);

Göründüyü kimi, define() $name-də göndərilmiş ada uyğun $value qiyməti mənimsədilmiş yeni sabit müəyyən edir. Vacib olmayan $case_sen parametri true olarsa irəlidə proqramın gedişatında sabitin adının reqistrləri də nəzərə alınır, əks halda nəzər alınmır. Sabitin silinməsi, ləğv edilməsi və yenidən təyin edilməsinə icazə verilmir. Nümunə:

define("pi", 3.14);
define("str", "Test string");
echo sin(pi / 4);
echo str;

Sabitin yaradılması zamanı adının dırnaq işarələri arasında yazılmasına fikir vermək lazımdır. Həmçinin, eyni adda ikinci sabiti təyin etməyin mümkün olmadığını nəzərdən qaçırmaq olmaz, bu halda proqramın yerinə yetirlməsi zamanı səhv çıxacaq.

Sabitin mövcudluğunun yoxlanılması

PHP-də həmçinin verilmiş adda sabitin mövcud olmamasını və ya təyin edilib edilməməsini yoxlayan funksiya mövcuddur:

bool defined(string $name);

$name adında sabit mövcuddursa true qaytarır.

Dinamik təyin edilmiş sabitlər

Hərdən, sabitləri dinamik olaraq proqramın yerinə yetirilməsi zamanı təyin etmək lazım gəlir. Bu zaman onların adını əvvəlcədən müəyyən etmək olmadığından proqramın mətnində əvvəldən onları yazmaq olmur. Belə hallarda sabitin qiymətini oxumaq üçün constant() funksiyasından istifadə edilir.

mixed constant(string $name)

Funksiya $name adlı sabitin dəyərini qaytarır. Göstərilmiş adda sabit mövcud deyilsə funksiya xəbərdalıq generasiya edir.

Növbəti nümunədə mt_rand() funksiyası ilə $index dəyişəninə 1-dən 10-a kimi təsadüfi bir rəqəm mənimsədilir və ondan sabitin formalaşdırılmasında istifadə edilir. Nəticədə hər dəfə proqram işə salınarkən sabitin adı mümkün 10 addan biri ola bilər. Belə sabitin dəyərini yalnız constant() funksiyası ilə əldə etmə olar.

<?php
  // 1-dən 10-a kimi təsadüfi bir ədəd generasiya edirik
  $index = mt_rand(1, 10);   // sabitin adı formalaşdırılır
  $name = "VALUE{$index}";  
  // Dinamik adlı sabiti təyin edirik
  define($name, 1);  
  echo constant($name); 
?>

İ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.

Mənimsətmə operatoru

Mənimsətmə – proqramlaşdırmada dəyişənlər ilə onların qiymətləri arasında əlaqələri dinamik olaraq dəyişməyə imkan verən mexanizmdir. Aydındır ki, qiymətin dəyişdirilməsi mənimsətmə əməliyyatının nəticəsidir və bir çox proqramlaşdırma dillərində bu əməliyyatın özü də müəyyən nəticə (adətən, mənimsədilən qiymətin eynisini) qaytarır. Fiziki olaraq isə mənimsətmə kompüterin yaddaşı və ya prosessorunun reqistrlərinə yazmaq və ya yenidən yazmaqdan ibarətdir.

Əvvəlki mövzularda bu operatorla rastlaşmışıq və PHP-də onun yazılış forması bərabər işarəsi – “=” kimidir. Sadə mənimsətmə əməliyyatının ümumi sintaksisi $dəyişənin_adı = qiymət; formasındadır. Əslində mənimsətmə əməliyyatının yazılış simvolunun seçilməsi proqramlaşdırma dillərinin yaradıcıları arasında çox mübahisələrə səbəb olur. Belə bir fikir var ki, = işarəsindən mənimsətməni işarələmək üçün istifadə edilməsi proqramlaşdırma dilinə iki operandın müqayisəsi üçün əlavə == işarəsini gətirməyə məcburiyyət yaradır və bu, proqramçıları dolaşığa salır, nəticədə mənimsətmə operatoru müqayisə operatoru ilə səhf salınır.

Bəzi dillərdə, məsələn C dilində if (a == b) { ... } əvəzinə if (a = b) { ... } yazsaq, yəni bilməyərəkdən = işarəsinin birini buraxmış olsaq kompilyator ən azı xəbərdarlıq göstərəcək. PHP-də isə məsələ fərqlidir. Bunu özünüzün də yoxlamağınız məsləhətdir.

$a = 0; $b = 0;
if($a = $b) echo "a və b eynidir";
else  echo "a və b fərqlidir";

İnterpretator heç nə hiss etdirməyəcək və proqram əminliklə “a və b eynidir” olduğunu bildirəcək. Göründüyü kimi proqram heç də düzgün nəticəni vermir. Buna səbəb $a = $b yazılışının məsələn, $a + $b kimi bir ifadə olmasıdır və bu yazılışın nəticəsi mənimsətmə operatorunun sağ tərəfinin qiymətinə, bizim halda 1-ə bərabərdir. Buna görə də belə məsələlərdə diqqətli olmaq mütləqdir.