Constructor ба destructor
Өмнөх хичээлд __construct() аргыг товчхон танилцсан. Энэ хичээлд constructor-ийн бүх боломжуудыг гүнзгийрүүлэн судална. Мөн түүний эсрэг хос болох __destruct() — объект устах мөчид ажилладаг арга — тай танилцана. Эдгээр хоёр арга нь PHP классын амьдралын мөчлөг (lifecycle)-ийг удирддаг чухал хэрэгсэл юм.
Constructor — объект төрөх мөч
__construct() нь new гэсэн үгээр объект үүсгэх мөчид автоматаар нэг удаа дуудагддаг. Шинж чанаруудыг эхлүүлэх, шаардлагатай нөхцөл шалгах, нөөц бэлдэх зэрэгт ашигладаг:
<?php
class Өгөгдлийн_сан {
private string $хост;
private string $нэр;
private bool $холбогдсон = false;
public function __construct(string $хост, string $нэр) {
$this->хост = $хост;
$this->нэр = $нэр;
// Холболтыг constructor-д эхлүүлнэ
$this->холбох();
}
private function холбох(): void {
// Жинхэнэ програмд PDO холболт нээнэ
$this->холбогдсон = true;
echo "'{$this->нэр}' өгөгдлийн санд холбогдлоо.\n";
}
public function холбогдсон_эсэх(): bool {
return $this->холбогдсон;
}
}
$дб = new Өгөгдлийн_сан("localhost", "myapp");
echo $дб->холбогдсон_эсэх() ? "Холбогдсон" : "Холбогдоогүй";
// "myapp" өгөгдлийн санд холбогдлоо.
// Холбогдсон
?>
Constructor-д шалгалт хийж, буруу утга ирвэл Exception шиддэг нь шилдэг дадал:
<?php
class Цалин {
public float $дүн;
public function __construct(float $дүн) {
if ($дүн < 0) {
throw new InvalidArgumentException("Цалин сөрөг байж болохгүй.");
}
$this->дүн = $дүн;
}
}
try {
$зөв = new Цалин(500_000); // ажиллана
$буруу = new Цалин(-1000); // Exception шидэнэ
} catch (InvalidArgumentException $e) {
echo "Алдаа: " . $e->getMessage(); // Алдаа: Цалин сөрөг байж болохгүй.
}
?>
PHP 8 — constructor property promotion
PHP 8.0-аас эхлэн constructor-д шинж чанарыг маш богино хэлбэрээр зарлаж болдог болсон. public/private/protected гэж параметрийн өмнө бичихэд автоматаар шинж чанар үүсэж, утга онооно:
<?php
// Уламжлалт хэлбэр — давтамжтай
class Хэрэглэгч_Хуучин {
public string $нэр;
public string $имэйл;
private int $нас;
public function __construct(string $нэр, string $имэйл, int $нас) {
$this->нэр = $нэр;
$this->имэйл = $имэйл;
$this->нас = $нас;
}
}
// PHP 8 богино хэлбэр — яг ижил үр дүн
class Хэрэглэгч {
public function __construct(
public string $нэр,
public string $имэйл,
private int $нас,
) {}
public function нас_авах(): int {
return $this->нас;
}
}
$х = new Хэрэглэгч("Болд", "bold@example.mn", 25);
echo $х->нэр; // Болд
echo $х->нас_авах(); // 25
?>
Хоёр хэлбэр яг ижил ажилладаг — PHP 8 хувилбар зүгээр л богино бичлэг юм.
Destructor — объект устах мөч
__destruct() нь объект санах ойгоос устах мөчид автоматаар дуудагддаг. Нээсэн файл хаах, log бичих, холболт таслах зэрэгт ашигладаг:
<?php
class Файл_Зохицуулагч {
private mixed $файл;
private string $нэр;
public function __construct(string $нэр) {
$this->нэр = $нэр;
$this->файл = fopen($нэр, 'a');
echo "'{$нэр}' файл нээгдлээ.\n";
}
public function бичих(string $мөр): void {
fwrite($this->файл, $мөр . "\n");
}
public function __destruct() {
if ($this->файл) {
fclose($this->файл);
echo "'{$this->нэр}' файл хаагдлаа.\n";
}
}
}
{
$лог = new Файл_Зохицуулагч('app.log');
$лог->бичих("[INFO] Програм эхэллээ");
$лог->бичих("[INFO] Хэрэглэгч нэвтэрлээ");
} // Энд $лог scope-оос гарахад destructor автоматаар дуудагдана
// Гаралт:
// 'app.log' файл нээгдлээ.
// 'app.log' файл хаагдлаа.
?>
fclose() гэж гараар дуудахаа мартсан ч destructor нь автоматаар хаадаг тул нөөц алдагдахаас хамгаалдаг.
Constructor ба destructor хамт
<?php
class Холболт {
private static int $тоолуур = 0;
public function __construct(public string $нэр) {
self::$тоолуур++;
echo "Холболт #{" . self::$тоолуур . "} нээгдлээ: {$this->нэр}\n";
}
public function __destruct() {
echo "Холболт хаагдлаа: {$this->нэр}\n";
self::$тоолуур--;
}
public static function идэвхтэй_тоо(): int {
return self::$тоолуур;
}
}
$а = new Холболт("үндсэн"); // Холболт #1 нээгдлээ: үндсэн
$б = new Холболт("нөөц"); // Холболт #2 нээгдлээ: нөөц
echo Холболт::идэвхтэй_тоо() . " холболт идэвхтэй\n"; // 2
unset($а); // Холболт хаагдлаа: үндсэн
echo Холболт::идэвхтэй_тоо() . " холболт идэвхтэй\n"; // 1
?>
Дараагийн хичээлд:
OOP-н хамгийн хүчтэй механизмуудын нэг болох өвлөлт (inheritance)-ийг судална. Нэг классаас шинэ класс үүсгэж, шинж чанар болон аргуудыг хэрхэн өвлөн авах, parent:: гэж хэрхэн ашиглахыг жишээгээр үзнэ.