为啥我不能将 PHP 类实例存储为 SESSION 变量
Posted
技术标签:
【中文标题】为啥我不能将 PHP 类实例存储为 SESSION 变量【英文标题】:Why can't I store a PHP class instance as a SESSION variable为什么我不能将 PHP 类实例存储为 SESSION 变量 【发布时间】:2010-10-10 20:22:26 【问题描述】:我有一个 php 脚本,它通过 Dojo Ajax xhrGet 调用以 2 种方式调用。 第一次使用“init”参数调用它,这会导致脚本创建 StateList 类的实例并读入状态名称文件。
session_start();
@include('StateList.php');
require_once('phplog.php');
//start executing here
$comd=$_GET['nexturl'];
if($comd=="init")
$st = new StateList("../data/statestxt.txt");
$_SESSION['statefile'] = $st;
第二次和更多次,另一个 xhrGet 调用传递一个“getstate”参数,以下代码尝试从 SESSION 数组中获取 StateList 类的实例。
if($comd =="getstate")
$st= $_SESSION['statefile'];
phplog("size=".$st->getSize());
但是,getSize() 方法永远不会执行,我也不能调用任何其他方法 在重构的 StateList 类实例上。
请注意,这是一个在顶部包含类定义的 PHP 脚本 因此类方法应该是已知的和可用的。
我在这里错过了什么?
【问题讨论】:
尽量避免使用@;只需正确编写代码,以免出现任何错误。 【参考方案1】:您可能需要serialize $st 对象/变量才能存储它。这将确保所有内容都保存到会话中。这绝对是使用object oriented 代码的方法。当你想再次使用数据时,你必须unserialize它。
【讨论】:
会话变量自动序列化和反序列化。【参考方案2】:在调用session_start()
之前需要包含类定义,否则对象将无法正确反序列化,将成为__PHP_Incomplete_Class
的实例。否则你所拥有的应该可以正常工作。
【讨论】:
如果我按照您的建议移动定义,则会话数组返回的值为空。 你有 display_errors on 和 error_reporting E_ALL 吗?你能确保第一个位实际上正在运行($comd=="init")吗?【参考方案3】:如果你要在会话中存储一个对象,它必须是link text。在 PHP 中序列化对象存在很多问题,更不用说将它们存储在会话中了。我建议不要完全这样做,并为您的问题找到不同的解决方案。但是,如果您打算这样做,则应查看应在类中定义的“魔术方法”link text,以促进从会话中调用它时的重新实例化。
【讨论】:
【参考方案4】:您是否启用了session.auto_start
?手册的会话页面指出,如果这样做,则必须以不同的方式加载类定义:
如果您打开 session.auto_start,那么将对象放入会话的唯一方法是使用 auto_prepend_file 加载其类定义,您将在其中加载类定义,否则您将不得不序列化您的对象并在之后取消序列化它。
http://php.net/manual/en/intro.session.php
正如该页面所说,对象的序列化/反序列化通常由 PHP 自动完成,但启用 session.auto_start
会改变这一点。
【讨论】:
【参考方案5】:这是难以单独调试的事情之一。在 PHP Sessions 中存储实例化的对象总是有点棘手,并且不能 100% 保证工作。下面是一些通用的调试技巧,可以帮助您解决这个问题。
首先,检查您的 apache 错误日志。您是否收到“调用非对象错误的方法”?如果是这样,这意味着您没有从会话中恢复对象。如果不是,是否有错误表明您的方法调用因其他原因而失败?
其次,检查一下您从会话中真正得到了什么。
if($comd =="getstate")
$st= $_SESSION['statefile'];
//get the class of st
phplog("instance=".get_class($st));
//get a reflection dump of st
$ref = new ReflectionClass($st);
$string = $ref->__toString();
phplog("reflection=".$string);
第三,查看存储在会话本身中的序列化字符串值。您实际上是在存储序列化对象吗?在您的开发环境中,将 php.ini 中的 session.save_path ini 值设置为 /tmp 之类的值,(或使用 ini_set 方法做同样的事情):
session.save_path = "/tmp"
然后检查在 /tmp(或任何文件夹)中创建的文件。您应该会看到一个以:
开头的字符串statefile:O:..........
实例化对象的类的名称也将包含在其中,以及保存到属性的值。
【讨论】:
【参考方案6】:试试这个:
include('StateList.php');
require_once('phplog.php');
// start your session after including your class file
session_start();
//start executing here
$comd=$_GET['nexturl'];
if($comd=="init")
$st = new StateList("../data/statestxt.txt");
$_SESSION['statefile'] = $st;
if($comd =="getstate")
// the ampersand creates a reference, preserving any further changes to your session data
$st = &$_SESSION['statefile'];
phplog("size=".$st->getSize());
【讨论】:
以上是关于为啥我不能将 PHP 类实例存储为 SESSION 变量的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Imagick 类不能将 pdf 文件转换为图像文件?