Какво точно е Singleton и какво са статичните данни? На този въпрос се опитват да си отговорят колегите от BGDev. Тук ще се опитам да хвърля малко светлина по въпроса.
Първо що е то статична данна?
Статични данни са такива, които са “живи” през целият период на изпълнение на приложението. Най-добре ще ме разберете с пример.
function static_test() {
static $a = null;
if( $a == null ) {
$a = 1;
echo ‘Първо извикване на функцията’;
} else {
echo ‘Всяко следващо’;
}
}
static_test();
static_test();
Ха сега, познайте какво ще се покаже при първото и после и при второто извикване?
След като очевидно схванахте как се използват статични данни нека да спомена, че за да може да имате достъп до статични данни в клас ( PHP, Java, а предполагам и други езици ) трябва да дефинирате метода си като статичен. Готиното на статичните методи, е че можете да ги извиквате без да се нуждаете от създаване на обект. Пак пример?
class StaticTest {
private static $test = “test”;
public function getTestNonStatic() {
echo $this->test;
}
public static function getTest() {
echo self::$test . ‘<br />’;
}
}
$StaticTest = new StaticTest();
$StaticTest->getTestNonStatic();
StaticTest::getTest();
Въпросният код дава следният изход:
Notice: Undefined property: StaticTest::$test in …
test
T.e. имате достъп до статични данни само от статични методи.
Сега малко за Singleton. Няма да обеснявам какво е Singleton, а направо ще ви покажа пример за Database клас, който използва такъв шаблон.
class Database {
private static $instance = null;
public static function getInstance() {
if( !self::$instance instanceof self ) {
self::$instance = new self;
}
return self::$instance;
}
private function __construct() {
global $host, $user, $pass, $dbname;
$this->connect( $host, $user, $pass, $dbname );
}
private function connect( $host, $user, $pass, $dbname ) {
$this->host = $host;
$this->user = $user;
echo ‘Host: ‘ . $host . ‘<br />’;
echo ‘User:’ . $user . ‘<br />’;
echo ‘Pass:’ . $pass . ‘<br />’;
echo ‘Name:’ . $dbname . ‘<br /><br />’;
}
public function query( $sql ) {
echo ‘Host: ‘ . $this->host . ‘<br />’;
echo $sql . ‘<br /><br />’;
}
}
$host = $user = $pass = $dbname = “Testing”;
$DBI = Database::getInstance();
$DBI->query( “SELECT .. “);
$DBI2 = Database::getInstance();
$DBI2->query( “INSERT INTO ..” );
Тук ще се наложат малко пояснения явно. ОК. Singleton шаблона е перфектен за извикване на инстанция на клас за връзка с база от данни. Защо? Защото хем е глобален т.е. можем от всяко кътче на PHP кода да си го да извикаме, хем прави само един път връзка към базата … а не 100, ако създавахме обект всеки път. Когато създаваме $DBI обекта, чрез статичният метод getInstance() всъщност се прави проверка дали вече е създаден въпросният обект. Ако не .. тогава правим нов, ако е – връщаме инстанция към него и го използваме. Катко забелязвате ( всъщност може да забележите тук 🙂 ) Данните за host, user, pass и т.н.т. се показват само един път от connect метода т.е. тук симулирам достъп до базата де .. но виждате резултатът. Та това е “сложният” Singleton шаблон.
Ако имате въпроси използвайте формата за коментари по надолу 🙂
4 replies on “Singleton, static и други подобни PHP щуротии”
Този най-популярен пример за Singleton винаги ми е бил малко странен, защото не е напълно функционален – ограничава те само до една конекция 🙂
Друго си е да си имаш:
$db1 = new Database($host1, $user1, $pass1, $db1);
$db2 = new Database($host2, $user2, $pass2, $db2);
А пък нищо не пречи колкото и пъти да ги викаш, конекциите да са само по една (по хост и потребител), и без Singleton.
Освен това, в примера ти конструктурът взима глобалните променливи $host, $user, $pass, $dbname. Какво става, ако те са различни при различни извиквания на Database::getInstance() – тогава само първата им стойност ще важи.
Философствам толкова много по една единствена причина – никога не съм ползвал Singleton и искам за себе си да разбера при каква ситуация ще ми е адекватно да го правя.
Поздрави,
Никола
Радвам се, че има коментари по темата 🙂
Относно конекциите към различни бази.
В примерът, който съм посочил е само за една конекция. Ако искаш да имаш повече от една, то ще трябва промениш ти функцията от private на public. Така не губиш Singleton шаблона, но вече ще можеш да създаваш нормални инстанции каквито искаш ти т.е. $db = new Database( $host, $user, $pass .. ); $db2 = new Database( $host2, $user2, $pass3 .. );
Но тук вече използването на Database::getInstance() ще връща последната създадена инстанция.
Глобални съм ги направил, защото при този метод няма как да ги предавам по друг начин, тъй като конструктура е private, а в случаят на единичната конекция не ти трябва повече усложнения.
На въпростът ти кога е адекватно да се използва – предимството идва от това, че след първото създаване на инстанцията и нужда от следващо извикване ( друг клас, метод или функция ) няма да се създава нов обект, а само ще направи една if проверка.
Другото удобство е, че тъй като е статична можеш да предаваш различна информация между класовете си, без да се нуждаееш от глобални променливи или константи.
Доста полезна информация мерси
чел съм малко Design Patterns (книгата) ама там беше написано много сложно
а ще бъде ли прекалено нахалство ако помоля да обясниш малко на чист български MVC модела най-основните неща без задълбаване
Тези дни ще пусна статия за MVC. Концепцията е много проста, но същевременно и вършеща огромна работа.