Static метод ба хувьсагч
Одоог хүртэл бид аргуудыг дуудахын тулд эхлээд new гэж объект үүсгэдэг байсан. Гэвч заримдаа объект огт шаардлагагүй — зүгээр л нэг тооцоо хийх, мэдээлэл авах, тохиргоо шалгах зэрэг үйлдэлд. Static метод болон хувьсагч нь яг ийм тохиолдолд тусалдаг: объект үүсгэхгүйгээр классаас шууд дуудаж болдог. static нь классын $this-гүй хэсэг гэж ойлгоход хялбар.
Static метод тодорхойлох
static түлхүүр үгээр тодорхойлж, :: (double colon) операторыг ашиглан дуудна:
<?php
class Математик {
// Static метод — объект үүсгэхгүйгээр дуудана
public static function дөрвөлжин(float $тоо): float {
return $тоо ** 2;
}
public static function хоёр_дахь_язгуур(float $тоо): float {
if ($тоо < 0) {
throw new InvalidArgumentException("Сөрөг тооны язгуур байхгүй.");
}
return sqrt($тоо);
}
public static function хамгийн_их(float ...$тоонууд): float {
return max($тоонууд);
}
}
// :: оператороор шууд дуудна — new хэрэггүй
echo Математик::дөрвөлжин(5); // 25
echo Математик::хоёр_дахь_язгуур(16); // 4
echo Математик::хамгийн_их(3, 7, 2, 9, 1); // 9
?>
:: операторыг scope resolution operator гэж нэрлэдэг. Static аргад $this байхгүй — учир нь объект үүсгэгдээгүй.
Static хувьсагч — классын нийтлэг санах ой
static хувьсагч нь тухайн классын бүх объектод нийтлэг — нэг объект өөрчилбөл бусад объектод тусгагдана. Объектын тоо тоолох, нийтлэг тохиргоо хадгалах зэрэгт их хэрэгтэй:
<?php
class Холболт_Тоолуур {
private static int $нийт_холболт = 0;
private static int $идэвхтэй = 0;
public function __construct(private string $нэр) {
self::$нийт_холболт++;
self::$идэвхтэй++;
echo "Холболт нээгдлээ: {$this->нэр} (идэвхтэй: " . self::$идэвхтэй . ")\n";
}
public function __destruct() {
self::$идэвхтэй--;
echo "Холболт хаагдлаа: {$this->нэр} (идэвхтэй: " . self::$идэвхтэй . ")\n";
}
public static function нийт(): int {
return self::$нийт_холболт;
}
public static function идэвхтэй(): int {
return self::$идэвхтэй;
}
}
$а = new Холболт_Тоолуур("үндсэн"); // идэвхтэй: 1
$б = new Холболт_Тоолуур("нөөц"); // идэвхтэй: 2
$в = new Холболт_Тоолуур("гуравдах"); // идэвхтэй: 3
echo "Нийт нээгдсэн: " . Холболт_Тоолуур::нийт() . "\n"; // 3
echo "Одоо идэвхтэй: " . Холболт_Тоолуур::идэвхтэй() . "\n"; // 3
unset($б); // идэвхтэй: 2
echo "Одоо идэвхтэй: " . Холболт_Тоолуур::идэвхтэй() . "\n"; // 2
?>
self:: нь $this-> шиг боловч static контекстод ашиглагддаг — "энэ класс" гэсэн утгатай.
Singleton загвар — нэг л объект
Static-ийн хамгийн алдартай хэрэглээ бол Singleton загвар юм: бүх програмд зөвхөн нэг объект үүсэхийг хангана. Тохиргоо, лог, өгөгдлийн сан холболт зэрэгт ашигладаг:
<?php
class Тохиргоо {
private static ?Тохиргоо $жишээ = null;
private array $утгууд = [];
// private constructor — гаднаас new хэрэглэж болохгүй болно
private function __construct() {
$this->утгууд = [
'апп_нэр' => 'Mongolian Dev Platform',
'хувилбар' => '1.0.0',
'хэл' => 'mn',
];
}
// Цорын ганц нэвтрэх цэг
public static function авах(): static {
if (static::$жишээ === null) {
static::$жишээ = new static();
}
return static::$жишээ;
}
public function утга_авах(string $түлхүүр): mixed {
return $this->утгууд[$түлхүүр] ?? null;
}
public function утга_тохируулах(string $түлхүүр, mixed $утга): void {
$this->утгууд[$түлхүүр] = $утга;
}
}
// Хаанаас ч дуудсан яг нэг л объект буцаана
$тохиргоо1 = Тохиргоо::авах();
$тохиргоо2 = Тохиргоо::авах();
$тохиргоо1->утга_тохируулах('хувилбар', '2.0.0');
echo $тохиргоо2->утга_авах('хувилбар'); // 2.0.0 — яг нэг объект тул хамт өөрчлөгдсөн
echo ($тохиргоо1 === $тохиргоо2) ? "Нэг объект мөн\n" : "Өөр объект\n"; // Нэг объект мөн
?>
static:: ба self:: — хожуу холболт
self:: нь код бичигдсэн классыг заадаг. static:: нь дуудагдаж буй бодит классыг заадаг — өвлөлттэй хамт ашиглахад ялгаа гарч ирдэг:
<?php
class Эх_Класс {
public static function self_жишээ(): static {
return new self(); // Үргэлж Эх_Класс үүсгэнэ
}
public static function static_жишээ(): static {
return new static(); // Дуудагдаж буй классыг үүсгэнэ
}
public static function нэр(): string {
return static::class; // Бодит классын нэр
}
}
class Хүүхэд_Класс extends Эх_Класс {}
$а = Хүүхэд_Класс::self_жишээ(); // Эх_Класс объект
$б = Хүүхэд_Класс::static_жишээ(); // Хүүхэд_Класс объект
echo get_class($а); // Эх_Класс
echo get_class($б); // Хүүхэд_Класс
echo Хүүхэд_Класс::нэр(); // Хүүхэд_Класс
?>
static:: нь late static binding гэж нэрлэгддэг — өвлөлттэй классуудад factory метод бичихэд маш хэрэгтэй.
Factory метод — static-ийн практик хэрэглээ
Static методыг "үүсгэгч" болгон ашиглаж, объект үүсгэх янз бүрийн арга санал болгодог загвар түгээмэл байдаг:
<?php
class Огноо {
private function __construct(
private int $жил,
private int $сар,
private int $өдөр
) {}
// Static factory методууд
public static function өнөөдөр(): static {
return new static(
(int)date('Y'),
(int)date('m'),
(int)date('d')
);
}
public static function мөрнөөс(string $огноо): static {
[$жил, $сар, $өдөр] = explode('-', $огноо);
return new static((int)$жил, (int)$сар, (int)$өдөр);
}
public function форматлах(): string {
return "{$this->жил} оны {$this->сар}-р сарын {$this->өдөр}";
}
}
$өнөөдөр = Огноо::өнөөдөр();
echo $өнөөдөр->форматлах(); // 2025 оны 1-р сарын 15
$тодорхой = Огноо::мөрнөөс('2024-12-31');
echo $тодорхой->форматлах(); // 2024 оны 12-р сарын 31
?>
Дараагийн хичээлд:
Namespace ойлголтыг судална. Том төслүүдэд классын нэрийн мөргөлдөөнийг хэрхэн зайлсхийдэг, use гэж хэрхэн оруулдаг, vendor namespace хэрхэн ажилладгийг жишээгээр үзнэ.