И снова здравствуйте:) : правильное использование Singleton

slego

Новичок
И снова здравствуйте:) : правильное использование Singleton

Подскажите, пожалуйста. Я что-то делаю неправильно. Хочу изобразить следующее:

есть класс базы данных DB который использует клас подключения DBConnection.
Класс DBConnection хотелось бы сделать в виде Singleton'а, т.е.
в приложении может быть множество классов DB, которые будут дружно использовать глобальный
класс DBConnection.

Насколько я понял про singleton, пытаюсь сделать следующее

index.php

PHP:
include_once("db.class.php");

DBConnection::instance("localhost;root;pass;db");

$db = &new DB();
$db->execQuery("SELECT * FROM messages");
while(!$db->eof())
{
	echo $db->fieldByName("message");
	$db->next();
}
db.class.php

PHP:
class DBConnection
{
    var $_connection;

    function DBConnection($connection)
    {
        list($db_host, $db_user, $db_pass, $db_name) = explode(";", $connection);
        $this->_connection = mysql_connect($db_host, $db_user, $db_pass);
        mysql_select_db($db_name, $this->_connection)
	}

	function getConnection()
	{
		return $this->_connection;
	}

	function &instance($connection)
	{
		static $db_connection;
		if(!$db_connection)
		{
			$db_connection = new DBConnection($connection);
		}
		return $db_connection;
	}
};

class DB
{
    var $_connection;

    function DB()
    {
    	//	ПРОБЛЕМА, СОБСТВЕННО ГДЕ-ТО ЗДЕСЬ
        $this->_connection = &DBConnection::getConnection();
    }
    function execQuery($sql)
    {
    	$res = mysql_query($sql, $this->_connection);
    	...
    }
    ...
};

Если код не очень ясен, то попытаюсь объяснить словами.
В самом начале скрипта инициализирую экземпляр класса DBConnection
(глобального, единственного на все приложение). Дальше, по мере надобности создаются
экземпляры класса DB. Внутри конструктора происходит
попытка подключения к бд, используя свойство глобального класса DBConnection.

Так вообще можно делать???
Большое спасибо.
 

vitus

мимо проходил
проблема здесь, а не там
function &instance($connection)
{
static $db_connection;
if(!$db_connection)
{
$db_connection = new DBConnection($connection);
}
return $db_connection;
}
-~{}~ 10.03.05 18:55:

ой, да и там - тоже :)
 

slego

Новичок
иии? ;)

-~{}~ 11.03.05 10:32:

если честно, именно в этом блоке я проблемы и не вижу: проверяется на неравенство NULL значение статической переменной $db_connection и, если все ок, создается объект класса DBConnection, иначе возвращается ссылка на уже созданный.
Что не так то? *8)
 

vitus

мимо проходил
кароче, чтоб грамоно использовать синглетон, его надо сначала грамотно написать :)

как ты использовал эту инстансе? её результат - кому-нибудь присвоил? - никому не присвоил...

при статическом вызове метода $this - указывает на объект в котором ты вызвал метод, а не на то что ты подумал, в статическом контексте $this не существует.
 

slego

Новичок
Ну я вот с этим как раз и не очень понял. Т.е., если в коде для инициализации прописать просто

DBConnection::instance("localhost;root;pass;db");

то это не прокатит?
Хорошо, а если сделать так

$foo = &DBConnection::instance("localhost;root;pass;db");

то будет ли инициализирован класс DBConnection?
Смогу ли я потом в любом месте скрипта обратиться к его функциям, например, так:

// somewhere deep in the code
...
$conn = DBConnection::getConnection();
...

?
 

vitus

мимо проходил
обратиться-то сможешь, только ничего хорошего не жди

$this->_connection никак не назначить при статическом вызове

сделай в нём
PHP:
    function &connection(){
        static $value;
         if(func_num_args()){           
            $value=func_get_arg(0); 
         } 
         return $value; 
    }
и вызывай чтоб
получить без параметров, чтоб назначить - с параметром

типа ClassName::connection($connection);
 

slego

Новичок
Хорошо, попробую еще раз привести пример, чего же я все-таки хочу добиться:
Допустим, есть класс логгирования, который должен заносить сообщения или в бд или в файл. Флаг нужного параметра передается в конструктор

PHP:
class Log
{
	var $_storage_type;

    function Log($storage_type)
    {
    	$this->_storage_type = $storage_type;
	}

    function set($message)
    {
    	switch ($this->_storage_type)
    	{
    	case "db":
    		//...
    		break;
    	case "file":
    		//...
    		break;
    	}
    }

}

Теперь имеется набор других классов, в которых по мере надобности
происходит занесение сообщений в лог


Я вижу два реальных способа как можно использовать механизм ведения логов в других классах:
1) во все классы, которые используют логгирование передавать тип хранилища,
т.е. что-то типа
PHP:
class A
{
	var $_log;
	function A($storage_type)
	{
		$this->_log = &new Log($storage_type);
	}
	function func()
	{
		$this->_log->set("wazz up maaan");
	}
}
2) из класса Log добираться до внешних настроек и выкоцивать от туда тип хранилища.

Из двух вариантов второй мне кажется более приемлемым, не смотря на некоторую
"несовместимость" с парадигмой ООП.

Когда начитался про синглтон, мне почему показалось (я очень сильно понадеялся), что существует третий способ, когда можно в самом начале инициализировать один единственный экземпляр класса, а потом его везде использовать как глобальный, т.е. забабахать все где-то так:

PHP:
Log::Log("db");

class A
{
	function func()
	{
		Log::set("wazz up maaan");
	}
}

class B
{
	function func()
	{
		Log::set("i'll gonna kill you mada-faka");
	}
}
P.S Как я понимаю, название "Log", наверное не очень удачно, т.к. скрипт
все время пытается вычислить логарифм :) ну да ладно.

-~{}~ 11.03.05 16:13:

Возможно есть решения по-элегантней без использования всяких синглтонов?
 

vitus

мимо проходил
с логом какраз - синглетон - самый подходячий случай
и logger::write("wazz up maaan"); - самое то что тебе надо,
если тебе не хочется заносить это всё в error_log

тока синглетон надо правильно написать :)
как написать - поищи по форуму - было тут такое
можно и моностейтом обойтиться.

а внешние настройки можно один раз грузануть при первом обращении.

статические поля можно через методы организовать, как я тебе раньше написал
 

slego

Новичок
Нагло пользуюсь твоей помощью, но еще несколько финальных (надеюсь) вопросиков :)

Автор оригинала: vitus
тока синглетон надо правильно написать :)
Правильно описать сам метод instance() или правильно написать обращение к нему?

а внешние настройки можно один раз грузануть при первом обращении.
так как я писал:
PHP:
$log = &Log::instance($storage_type)
?
статические поля можно через методы организовать, как я тебе раньше написал
имеется в виду
PHP:
function &connection(){ 
        static $value; 
         if(func_num_args()){            
            $value=func_get_arg(0); 
         } 
         return $value; 
    }
?
 

vitus

мимо проходил
1. синглетон - это не только метод инстансе, это такой класс, у которого может сусчествовать только один экземпляр, это значит что его объекты нельзя создавать конструктором, нельзя их копировать (или нужно сделать так, чтобы это ничего не меняло) и сделать в нём один единственный метод доступа, обычно его называют getInstance(), который вызывается без параметров и возвращает этот самый единственный экземпляр.

2. logger::storage($storage_type);

3. - да типа так и storage() - тоже так

-~{}~ 11.03.05 17:48:

ещё скажу :)
в пхп4 надо делать моностейт, - это такой класс, экземпляры которого создавать бессмысленно, тоесть он не пользуется внутри себя $this и всё что в нём есть - статично наглухо, тоесть даже getInstance() в нём не нужен
 

slego

Новичок
огромное тебе человеческое спасибо! Выражаю тебе искреннее уважение.
 
Сверху