为啥我不能将 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 变量的主要内容,如果未能解决你的问题,请参考以下文章

我可以将类实例存储在 $_SESSION 空间中吗?

为啥 Imagick 类不能将 pdf 文件转换为图像文件?

为啥 Asp.net MVC4 不能使用 SQL Server Session 状态存储的 cookieless

PHP - 为啥我不能摆脱这个会话 id cookie?

为啥我不能将泛型类型的一个实例转换为另一个实例?

购物车类分析session+single