На недавно отпиареном здесь ресурсе наткнулся на вопрос о хранении в сессии php созданных в скрипте объектов.
Насколько плохой практикой является в принципе хранение объектов в сессии, я обсуждать не буду, а просто покажу, как надо работать с такими объектами. Впрочем, если специалисты уже нашли рецепт на php.net, и считают, что все тривиально, я с ними полностью соглашусь. Однако если вы немного не в курсе…
Итак, мы задались целью положить в сессию объект, скажем, некоего пользователя.
Примерно наши файлы будут выглядеть так:
myclass.php:
index.php:
А теперь разберёмся, что мы делаем.
В первый запуск скрипта index.php мы создаем объект класса myclass и помещаем его в сессию. В любом последующем случае (пока мы не уничтожим сессию или не уничтожим на неё «ссылку» — в виде куки в браузере, например) мы загружаем сессию, в которой уже есть наш объект. Однако вместо того, чтобы быть экземпляром класса MyClass, var_dump() нас «радует» классом "__PHP_Incomplete_Class":
Всё очень просто. При инициализации сессии php натыкается на факт, что у него в $_SESSION['classTst'] лежит экземпляр класса MyClass (желающие могут посмотреть на содержимое файла (если у вас сессии в файлах) сессии и убедиться, что там будет лежать наш сериализованный объект, с описанием, экземпляром какого класса он является). Но (сюрприз!), как видно из скрипта, php на момент старта сессии НИЧЕГО не знает о существовании класса MyClass. Посему вполне логичный интерпретатор воспринимает далее этот объект именно как объект некоего __PHP_Incomplete_Class.
Но стоит нам поменять порядок старта сессии и загрузки класса:
как, вуаля, мы получаем то, что и хотели:
В общем, всё действительно просто: все объекты, которые вы хотите хранить в сессии, должны стать известны интерпретатору ДО того, как вы будете стартовать сессию.
Таким образом, например, если у вас стандартом является session.auto_start On, хранить в сессии объекты вам не судьба. Также, если вы полагаетесь на фреймворки, авторы которых за вас решили, где и когда какие объекты подгружать (и вы всецело полагаетесь на авторов), хранение каких-то определённых объектов в сессии может стать просто смертельным номером (в случае объекта с другими вложенными объектами, вызываемыми «по требованию» где-то перед исполнением, скажем, уже контроллера, когда сессия давно стартовала). В случае составного объекта (содержащего в себе 2-3 служебных объекта в свойствах, например) может возникнуть резонный вопрос: что «дешевле» — кинуть всё в сессию, или получить заново объект одним-двумя запросами из БД (или кэша БД)?
Так что хранить или не хранить в сессии объекты, и как это делать исходя из реалий вашего проекта — решать всё равно вам :)
Насколько плохой практикой является в принципе хранение объектов в сессии, я обсуждать не буду, а просто покажу, как надо работать с такими объектами. Впрочем, если специалисты уже нашли рецепт на php.net, и считают, что все тривиально, я с ними полностью соглашусь. Однако если вы немного не в курсе…
Итак, мы задались целью положить в сессию объект, скажем, некоего пользователя.
Примерно наши файлы будут выглядеть так:
myclass.php:
<?php
class MyClass
{
public $user;
}
index.php:
<?php
session_start();
require 'myclass.php';
header("content-type: text/plain");
if (!isset($_SESSION['classTst'])) {
$myclass = new MyClass();
$myclass->user = 'me';
$_SESSION['classTst'] = $myclass;
echo "Class is into session array now";
}
else {
echo "\$_SESSION['classTst'] dump: \n\n";
var_dump($_SESSION['classTst']);
}
А теперь разберёмся, что мы делаем.
В первый запуск скрипта index.php мы создаем объект класса myclass и помещаем его в сессию. В любом последующем случае (пока мы не уничтожим сессию или не уничтожим на неё «ссылку» — в виде куки в браузере, например) мы загружаем сессию, в которой уже есть наш объект. Однако вместо того, чтобы быть экземпляром класса MyClass, var_dump() нас «радует» классом "__PHP_Incomplete_Class":
$_SESSION['classTst'] dump: object(__PHP_Incomplete_Class)#1 (2) { ["__PHP_Incomplete_Class_Name"]=> string(7) "MyClass" ["user"]=> string(2) "me" }
Всё очень просто. При инициализации сессии php натыкается на факт, что у него в $_SESSION['classTst'] лежит экземпляр класса MyClass (желающие могут посмотреть на содержимое файла (если у вас сессии в файлах) сессии и убедиться, что там будет лежать наш сериализованный объект, с описанием, экземпляром какого класса он является). Но (сюрприз!), как видно из скрипта, php на момент старта сессии НИЧЕГО не знает о существовании класса MyClass. Посему вполне логичный интерпретатор воспринимает далее этот объект именно как объект некоего __PHP_Incomplete_Class.
Но стоит нам поменять порядок старта сессии и загрузки класса:
<?php
require 'myclass.php';
session_start();
header("content-type: text/plain");
if (!isset($_SESSION['classTst'])) {
$myclass = new MyClass();
$myclass->user = 'me';
$_SESSION['classTst'] = $myclass;
echo "Class is into session array now";
}
else {
echo "\$_SESSION['classTst'] dump: \n\n";
var_dump($_SESSION['classTst']);
}
,как, вуаля, мы получаем то, что и хотели:
$_SESSION['classTst'] dump: object(MyClass)#1 (1) { ["user"]=> string(2) "me" }
В общем, всё действительно просто: все объекты, которые вы хотите хранить в сессии, должны стать известны интерпретатору ДО того, как вы будете стартовать сессию.
Таким образом, например, если у вас стандартом является session.auto_start On, хранить в сессии объекты вам не судьба. Также, если вы полагаетесь на фреймворки, авторы которых за вас решили, где и когда какие объекты подгружать (и вы всецело полагаетесь на авторов), хранение каких-то определённых объектов в сессии может стать просто смертельным номером (в случае объекта с другими вложенными объектами, вызываемыми «по требованию» где-то перед исполнением, скажем, уже контроллера, когда сессия давно стартовала). В случае составного объекта (содержащего в себе 2-3 служебных объекта в свойствах, например) может возникнуть резонный вопрос: что «дешевле» — кинуть всё в сессию, или получить заново объект одним-двумя запросами из БД (или кэша БД)?
Так что хранить или не хранить в сессии объекты, и как это делать исходя из реалий вашего проекта — решать всё равно вам :)