Всем большой привет! Решил в очередном проекте реализовать сессии по-своему, на б.д. Не то, чтобы меня не устраивают стандартные сессии, но вот так захотелось, наверно из спортивного интереса. Сайт врядли когда-либо станет высоконагруженным проектом. Поскольку уже привык к простоте и удобству встроенных в php сессий (просто вносишь изменения в массив и оно всё само запоминается), захотел, чтобы мой алгоритм, хранящий данные в б.д., работал по аналогичному принцыпу. В конструкторе класса сессий должны получаться данные сессии и как-то передаваться в основную программу, ну а деструктор должен иметь доступ к обновлённому массиву переменных сессии, чтобы посмотреть, что там изменилось и при необходимости сохранить изменения в б.д. Сама работа с б.д. и проверка - что изменилось, что нет (что надо обновить, если надо) - тут всё просто. Основное, что меня интересует - как в деструкторе получить доступ к массиву сессии без вызова каких-то дополнительных методов (и передачи параметров) из основной программы. Я тут посидел, поэксперементировал и у меня получился такой тестовый код: PHP: <?php class test { private $data; public function __construct(&$Session = array()) { $this->data = &$Session; $this->data = array( 'a' => 'b', 'c' => 'd' ); } public function __destruct() { echo('<pre>In destruct: '); print_r($this->data); echo('</pre>'); } } $test = new test($Session); unset($Session['a']); $Session['e'] = 'f'; ?> Оно работает так, как мне и надо. Вывод скрипта: Код (Text): In destruct: Array ( [c] => d [e] => f ) А спросить хочу - это вообще, нормально? Т.е. это должно работать и в других версиях PHP (у меня 5.2.1 сейчас на локалхосте) или тут есть какой-то косяк?
sobachnik Пора бы уже на 5.3 перелезать PHP: <?php class TestSession { private $data = array( 'a' => 'b', 'c' => 'd' ); function __get($name) { return $this->$name; } function __set($name, $value) { $this->$name = array_merge($this->data, $value); return array_shift($this->$name); } } $session = new TestSession(); $session->push = array('e' => 'f'); print_r($session->push); Код (Text): Array ( [c] => d [e] => f )
session.php PHP: <?php define ( 'WRX_SESSION_NAME', 'WRXSID' ); define ( 'WRX_SESSION_LIFETIME', 300 ); // активность юзера. если че - удаляем class WRXToolsSession { const TABLE = 'wek_sessions'; /** * Сессия * @var string */ private $sSID = null; private $iCalls; private $iStart; private $iUpdate; private $aData; /** * @return WRXToolsSession WRXToolsSession */ static function getInstance() { static $oHandler = null; if (is_null ( $oHandler )) { $oHandler = new WRXToolsSession (); } return $oHandler; } public function __construct() { } /** * @return WRXToolsDb WRXToolsDb */ private function getDb() { $oCore = WRXCore::getInstance (); $oDB = $oCore->addTools ( 'WRXToolsDb' ); /* @var $oDB WRXToolsDb */ return $oDB; } public function Init() { if (! isset ( $_COOKIE [WRX_SESSION_NAME] )) { $this->setSid ( WRXToolsGUID::getGUID () ); $this->Create (); } else { $this->setSid ( $_COOKIE [WRX_SESSION_NAME] ); $this->Get (); } setcookie ( WRX_SESSION_NAME, rawurlencode ( $this->getSid () ), 0, '/', $_SERVER ['HTTP_HOST'] ); //setcookie ( WRX_SESSION_NAME, rawurlencode ( $this->getSid () ) ); } public function Create() { $oDB = $this->getDb(); $iNow = time (); $this->iCalls = 1; $this->iStart = $this->iUpdate = $iNow; $this->aData = array (); $sSQL = " INSERT INTO `".self::TABLE."` SET `ses_name` = '" . $oDB->escape ( $this->getSid () ) . "', `ses_calls` = " . $this->getCalls () . ", `ses_start` = {$iNow}, `ses_update` = {$iNow}, `ses_data` = '" . $oDB->escape ( $this->getDataSerialize () ) . "' "; $oDB->query ( $sSQL ); $this->CleanUp(); } private function CleanUp() { $sSQL = " DELETE FROM `".self::TABLE."` WHERE `ses_update` < ".(time() - WRX_SESSION_LIFETIME)." "; $this->getDb()->query ( $sSQL ); } public function Get() { $oDB = $this->getDb(); $sSQL = " SELECT * FROM `".self::TABLE."` WHERE `ses_name` = '" . $oDB->escape ( $this->getSid () ) . "' "; $oObject = $oDB->getObject ( $sSQL ); if ($oObject === false) { $this->setSid ( WRXToolsGUID::getGUID () ); $this->Create (); $this->Get (); } else { $this->iCalls = $oObject->ses_calls; $this->iStart = $oObject->ses_start; $this->iUpdate = $oObject->ses_update; $this->setDataSerialize ( $oObject->ses_data ); } } public function Update() { $oDB = $this->getDb(); $this->iCalls ++; $this->iUpdate = time (); $sSQL = " UPDATE `".self::TABLE."` SET `ses_calls` = " . $this->iCalls . ", `ses_update` = " . $this->iUpdate . ", `ses_data` = '" . $oDB->escape ( $this->getDataSerialize () ) . "' WHERE `ses_name` = '" . $oDB->escape ( $this->getSid () ) . "' "; $oDB->query ( $sSQL ); } public function Delete() { $oDB = $this->getDb(); $sSQL = " DELETE FROM `".self::TABLE."` WHERE `ses_name` = '" . $oDB->escape ( $this->getSid () ) . "' "; $oDB->query ( $sSQL ); } public function getDataSerialize() { return serialize ( $this->aData ); } public function setDataSerialize($sData) { if (empty ( $sData )) $sData = serialize ( array () ); return $this->aData = unserialize ( $sData ); } public function setSid($sSid = null) { $this->sSID = $sSid; } /** * Возвращает идентификатор сессии */ public function getSid() { return $this->sSID; } /** * Записывает в в свойство класса пару ключ-значение * * @param string $sName * @param mixed $mValue */ public function setValue($sName, $mValue) { $this->aData [$sName] = $mValue; return $mValue; } /** * Возвращает значение по ключу * * @param string $sName * @param mixed $mDefault * @return mixed */ public function getValue($sName, $mDefault = null) { return isset ( $this->aData [$sName] ) ? $this->aData [$sName] : $mDefault; } /** * Удаляет переменную из сессии * * @param $sName * @return void */ public function delValue($sName) { unset ( $this->aData [$sName] ); } public function getTimeStart() { return $this->iStart; } public function getTimeUpdate() { return $this->iUpdate; } public function getTimeEnd() { return $this->iUpdate + WRX_SESSION_LIFETIME; } public function getCalls() { return $this->iCalls; } /** * Деструктор, вызывает finishWriteSession * */ public function __destruct() { } } index.php PHP: <?php require_once "../core/loader.php"; $oCore = WRXCore::getInstance (); WRXToolsSession::getInstance ()->Init(); $oUser = WRXUser::getInstance()->Track(); $oHTTPRequest = $oCore->addTools ( 'WRXHttpRequest' ); /* @var $oHTTPRequest WRXHttpRequest */ list ( $sClass, $sMethod ) = $oHTTPRequest->getEntity (); try { $oClass = new $sClass (); } catch ( WRXException $e ) { throw new WRXException ( "Can't create entity [$sClass]", 0, __FILE__, __LINE__ ); } $sHTML = $oClass->$sMethod (); WRXToolsSession::getInstance ()->Update (); echo $sHTML; [sql] -- -- Структура таблицы `wek_sessions` -- CREATE TABLE IF NOT EXISTS `wek_sessions` ( `ses_name` varchar(36) NOT NULL default '00000000-0000-0000-0000-000000000000', `ses_calls` int(10) unsigned NOT NULL default '0', `ses_start` int(11) NOT NULL, `ses_update` int(11) NOT NULL, `ses_data` text, PRIMARY KEY (`ses_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; [/sql]