Где-то несколько дней вот изучаю паттерны, вещь весьма занятная. :)
Особенно меня заинтересовал паттерн "синглтон". Сразу же в голову приходит работа с бд. Где все приложение использует одно соединение.
Вот сделал небольшой скрипт.
Описание: есть две базы, в одной хранятся страны, в другой города. У этих таблиц есть три поля, id, имя, имя по русски.
цель: сделать вывод стран и городов. Сразу скажу цель обобщенная.
Для работы с бд существует класс-одиночка DBConn:
class DBConn
{
static private $_instance = null;
private $_db;
private function __clone(){}
private function __construct()
{
echo "connect!<br/>";
$this->_db = new PDO("mysql:host=localhost; dbname=you_db_name", "UserName", "UserPassword"); //соединение
}
static function getInstance()
{
if (self::$_instance == null)
{
self::$_instance = new DBConn();
}
return self::$_instance;
}
function getDb()
{
return $this->_db;
}
}
здесь я думаю все понятно, если объекта нет - создается. Через функцию getDb получаю соединение с базой.
Далее есть классы стран и городов, IdCountry и IdCity соответственно:
class IdName
{
protected $id;
protected $name;
protected $ru_name;
function getName()
{
return $this->name;
}
function getRuName()
{
return $this->ru_name;
}
}
class IdCountry extends IdName
{
}
class IdCity extends IdName
{
}
они унаследует некоторые общие черты от родителя IdName, так как в будущем возможно будут классы не только городов, но например других наименований (со своими особенными свойствами, но имя и имя по русски одно для всех :) ).
Не удивляйтесь что классы стран и городов пустые, там будут свои методы, я не стал пока на этом закорачиваться.
Далее я сделал два класса для выборок или стран или городов - BrowseCountry и BrowseCity.
Оба наследуются от BrowseMain, так как есть общие свойства, а реализации у многих может быть разной.
Так же я решил попробовать и паттерн "фабрика". Не знаю к месту ли. :D Но попытка не пытка...
Рассмотрим например выборку стран. У класса есть свойство $_country - оно хранит массив выбранных из базы стран. Есть общее для всех классов "Browse*" свойство sql- оно хранит соединение с базой. Тут я думаю правильно я тут все сделал (. Меня грызут сомнения. а не будет ли например при каждой передаче соединения через getDb в sql плодится сколько угодно соединений. Прошу извинить за тавтологию
Ну а далее я думаю все понятно.
class BrowseFactory
{
static $OBJ;
static function create($n)
{
switch ($n)
{
case "BrowseCountry":
self::$OBJ = new BrowseCountry();
break;
case "BrowseCity":
self::$OBJ = new BrowseCity();
break;
}
return self::$OBJ;
}
}
class BrowseMain
{
protected $sql;
protected $stmt;
protected $show_str;
function getStr()
{
return $this->show_str;
}
}
class BrowseCountry extends BrowseMain
{
private $_country;
function __construct()
{
try
{
$this->sql = DBConn::getInstance()->getDb();
$this->stmt = $this->sql->query("SELECT * FROM country_list");
$this->_country = $this->stmt->fetchAll(PDO::FETCH_CLASS, "IdCountry");
} catch (PDOException $e)
{
echo $e->getMessage();
}
foreach ($this->_country as $p)
{
$this->show_str .= $p->getName() . "<hr/>";
}
}
}
class BrowseCity extends BrowseMain
{
private $_city;
function __construct()
{
try
{
$this->sql = DBConn::getInstance()->getDb();
$this->stmt = $this->sql->query("SELECT * FROM city_list");
$this->_city = $this->stmt->fetchAll(PDO::FETCH_CLASS, "IdCity");
} catch (PDOException $e)
{
echo $e->getMessage();
}
foreach ($this->_city as $c)
{
$this->show_str .= $c->getName() . "<hr/>";
}
}
}
Ну и сам запуск выборок и вывод:
$browse_country = BrowseFactory::create("BrowseCountry");
echo "<b>Country</b><br/>".$browse_country->getStr();
$browse_city = BrowseFactory::create("BrowseCity");
echo "<b>City</b><br/>".$browse_city->getStr();
Как вы думаете на правильном ли я пути? И что в данном примере не правильно на ваш взгляд.
Заранее спасибо что потратили время на просмотр моего г#$@о кода.
Спустя 3 часа, 29 минут, 52 секунды (11.04.2011 - 04:40) kirik написал(а):
Цитата (Zhandos @ 10.04.2011 - 18:10) |
не будет ли например при каждой передаче соединения через getDb в sql плодится сколько угодно соединений |
Да нет.. метод DBConn::getInstance создаст экземпляр себя (вызовет конструктор) только один раз, а следовательно откроется только одно соединение.
Я бы вам посоветовал использовать вместо названия классов внутри себя - магическую
Спустя 8 часов, 38 минут, 59 секунд (11.04.2011 - 13:19) Zhandos написал(а):
Я просто думал если сделать присваивание переменной
переменная $_db скопируется в sql.
Вот я провел небольшой эксперимент:
И получается если где-то меняю переменную test_varr она меняется везде. То есть $obj1 и $obj2 являются ссылками, а не полноценными объектами?
Хотелось что бы кто-нибудь объяснил суть. :blink:
sql = DBConn::getInstance()->getDb();
переменная $_db скопируется в sql.
Вот я провел небольшой эксперимент:
class TestSingle
{
static private $_instance = null;
public $test_varr = 1; //for example
private function __construct()
{
echo "create singleton<br/>";
}
private function __clone(){}
static function getInstance()
{
if (self::$_instance == null)
{
self::$_instance = new TestSingle();
}
return self::$_instance;
}
}
$obj1 = TestSingle::getInstance();
$obj2 = TestSingle::getInstance();
TestSingle::getInstance()->test_varr = 100;
echo "obj1_varr: ".$obj1->test_varr." obj2_varr: ".$obj2->test_varr." singleton_varr: ".TestSingle::getInstance()->test_varr."<br/>";
$obj1->test_varr = 33;
echo "obj1_varr: ".$obj1->test_varr." obj2_varr: ".$obj2->test_varr." singleton_varr: ".TestSingle::getInstance()->test_varr."<br/>";
И получается если где-то меняю переменную test_varr она меняется везде. То есть $obj1 и $obj2 являются ссылками, а не полноценными объектами?
Хотелось что бы кто-нибудь объяснил суть. :blink:
Спустя 15 минут, 25 секунд (11.04.2011 - 13:35) Nikitian написал(а):
Так вы реализуете синглтон и хотите, чтобы он работал как отдельные объекты. На то синглтон и нужен, чтобы создав его в разных местах получить один и тот же объект, а не несколько разных.
Спустя 4 минуты, 26 секунд (11.04.2011 - 13:39) neadekvat написал(а):
Цитата (Zhandos @ 11.04.2011 - 14:19) |
То есть $obj1 и $obj2 являются ссылками, а не полноценными объектами? |
Формально - да, это всего лишь ссылки на объекты в памяти. Вопрос только в том, на какие объекты. На один и тот же или на разные.
В вашем случаи на один и тот же.
Спустя 25 минут, 46 секунд (11.04.2011 - 14:05) Oyeme написал(а):
Да ссылками как же ещё.
Для клонирования объекта используй
Хотя зачем ты так всё усложняешь.
Для клонирования объекта используй
$obj2 = clone $obj1;
Хотя зачем ты так всё усложняешь.
Спустя 8 минут, 27 секунд (11.04.2011 - 14:13) Zhandos написал(а):
Все понятно. Просто я заблуждался что передавая через return экземпляр синглтона он будет копироваться в переменную.
Спасибо всем! Надеюсь я не показался совсем уж тупым
. Я только учусь.
Хороший тут форум, останусь тут. Надеюсь я никого не напрягаю?
Спасибо всем! Надеюсь я не показался совсем уж тупым
![rolleyes.gif](http://phpforum.ru/html/emoticons/rolleyes.gif)
Хороший тут форум, останусь тут. Надеюсь я никого не напрягаю?
![laugh.gif](http://phpforum.ru/html/emoticons/laugh.gif)
Спустя 22 минуты, 20 секунд (11.04.2011 - 14:36) neadekvat написал(а):
Цитата (Zhandos @ 11.04.2011 - 15:13) |
Надеюсь я не показался совсем уж тупым |
Да бросьте, ООП - не самая простая вещь.
Посидите тут, увидите, какие порой вопросики задают..
Спустя 7 часов, 17 минут, 50 секунд (11.04.2011 - 21:54) kirik написал(а):
Цитата (Zhandos @ 11.04.2011 - 07:13) |
Просто я заблуждался что передавая через return экземпляр синглтона он будет копироваться в переменную. |
Это было верно для PHP4.