PHP / Хамрах хүрээ (Scope)

Хамрах хүрээ (Scope)

Хувьсагч кодын аль хэсгээс харагдах вэ? Энэ асуултын хариулт бол scope — хамрах хүрээ юм. Scope буруу ойлговол "Хувьсагч байхгүй байна" гэсэн алдаа гарч, яагаад болохыг нь ухаарахад хэцүү байдаг. Энэ хичээлд PHP-ийн scope-ийн дүрмүүдийг бүрэн ойлгоно.

Локал scope — функц дотрын хувьсагч

Функц дотор зарлагдсан хувьсагч зөвхөн тэр функц дотроо амьдардаг — гаднаас харагдахгүй:

php
<?php
function тооцоолох(): void {
    $үр_дүн = 42;          // Энэ хувьсагч зөвхөн функц дотор байна
    echo $үр_дүн;          // 42 ✓
}

тооцоолох();

// Функцнаас гадна хандах оролдлого
echo $үр_дүн;              // ⚠ Notice: Undefined variable $үр_дүн
?>

Мөн эсрэгээр — функц нь гаднах хувьсагчийг шууд харж чаддаггүй:

php
<?php
$нэр = "Батбаяр";          // Глобал хувьсагч

function хэвлэх(): void {
    echo $нэр;              // ⚠ Undefined variable — функц гаднаас харахгүй!
}

хэвлэх();   // (хоосон)

// Зөв арга — параметрээр дамжуулна
function зөв_хэвлэх(string $нэр): void {
    echo $нэр;
}

зөв_хэв_хэвлэх($нэр);    // Батбаяр ✓
?>

global түлхүүр үг

Функц дотроос глобал хувьсагчид хандах шаардлага гарвал global зарлана. Гэхдээ энийг хэт их ашиглах нь кодыг уян хатан бус болгодог тул болгоомжтой хэрэглэх хэрэгтэй:

php
<?php
$тоолуур = 0;
$лог = [];

function нэмэх(int $хэмжээ): void {
    global $тоолуур, $лог;  // Глобал хувьсагчийг дотор оруулна

    $тоолуур += $хэмжээ;
    $лог[] = "Нэмэгдэл: +$хэмжээ → нийт $тоолуур";
}

нэмэх(10);
нэмэх(5);
нэмэх(20);

echo $тоолуур;              // 35
print_r($лог);
// Array (
//   [0] => Нэмэгдэл: +10 → нийт 10
//   [1] => Нэмэгдэл: +5 → нийт 15
//   [2] => Нэмэгдэл: +20 → нийт 35
// )
?>

$GLOBALS суперглобал массивыг ашиглан мөн адил хандаж болно:

php
<?php
$оноо = 100;

function оноо_хасах(int $хасах): void {
    $GLOBALS["оноо"] -= $хасах;   // global зарлахгүйгээр
}

оноо_хасах(15);
echo $оноо;   // 85
?>

static хувьсагч

Ердийн локал хувьсагч функц дуусахад устдаг. static хувьсагч дуудалт хооронд утгаа хадгалдаг:

php
<?php
function дуудалт_тоолох(): int {
    static $тоо = 0;   // Зөвхөн анх нэг удаа 0 болгож эхлэнэ
    $тоо++;
    return $тоо;
}

echo дуудалт_тоолох();   // 1
echo дуудалт_тоолох();   // 2
echo дуудалт_тоолох();   // 3

// Ердийн локал хувьсагчтай харьцуулалт
function ердийн_тоолуур(): int {
    $тоо = 0;   // Дуудалт бүрт 0-с эхэлнэ
    $тоо++;
    return $тоо;
}

echo ердийн_тоолуур();   // 1
echo ердийн_тоолуур();   // 1  ← хэзээ ч нэмэгдэхгүй
echo ердийн_тоолуур();   // 1
?>

static хувьсагчийн хэрэглээний жишээнүүд:

php
<?php
// Нэг удаа тооцоолж кэшлэх
function тохиргоо_авах(string $түлхүүр): string {
    static $кэш = [];

    if (!isset($кэш[$түлхүүр])) {
        // Зөвхөн анх нэг удаа уншина (жишээлбэл файлаас)
        $кэш[$түлхүүр] = "тохиргооны_утга_$түлхүүр";
        echo "(файлаас уншлаа) ";
    }

    return $кэш[$түлхүүр];
}

echo тохиргоо_авах("db_host");   // (файлаас уншлаа) тохиргооны_утга_db_host
echo тохиргоо_авах("db_host");   // тохиргооны_утга_db_host (кэшээс)
echo тохиргоо_авах("db_host");   // тохиргооны_утга_db_host (кэшээс)
?>

Scope-ийн дүрмүүд товчоор

php
<?php
$глобал = "би глобал";      // Файлын дээд түвшний хувьсагч

function scope_жишээ(): void {
    // 1. Глобал хувьсагч гаднаас шууд харагдахгүй
    // echo $глобал;  ← undefined

    // 2. global ашиглан оруулж болно
    global $глобал;
    echo $глобал;            // би глобал

    // 3. Локал хувьсагч зарлах
    $локал = "би локал";
    echo $локал;             // би локал
}

scope_жишээ();

// 4. Функц дуусахад локал хувьсагч устна
// echo $локал;  ← undefined

// 5. Глобал хувьсагч функцнаас гадна хэвийн харагдана
echo $глобал;               // би глобал
?>

Дараагийн хичээлд:

Жагсаалт массивыг — indexed array — судална. Массив үүсгэх, элемент нэмэх, устгах, хандах, давталтаар тойрох болон count() зэрэг үндсэн функцүүдийг үзнэ.