<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/ref.session.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'zh',
  ),
  'this' => 
  array (
    0 => 'function.session-set-save-handler.php',
    1 => 'session_set_save_handler',
    2 => '设置用户自定义会话存储函数',
  ),
  'up' => 
  array (
    0 => 'ref.session.php',
    1 => 'Session 函数',
  ),
  'prev' => 
  array (
    0 => 'function.session-set-cookie-params.php',
    1 => 'session_set_cookie_params',
  ),
  'next' => 
  array (
    0 => 'function.session-start.php',
    1 => 'session_start',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'zh',
    'path' => 'reference/session/functions/session-set-save-handler.xml',
  ),
  'history' => 
  array (
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="function.session-set-save-handler" class="refentry">
 <div class="refnamediv">
  <h1 class="refname">session_set_save_handler</h1>
  <p class="verinfo">(PHP 4, PHP 5, PHP 7, PHP 8)</p><p class="refpurpose"><span class="refname">session_set_save_handler</span> &mdash; <span class="dc-title">设置用户自定义会话存储函数</span></p>

 </div>

 <div class="refsect1 description" id="refsect1-function.session-set-save-handler-description">
  <h3 class="title">说明</h3>
  <div class="methodsynopsis dc-description">
   <span class="methodname"><strong>session_set_save_handler</strong></span>(<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$open</code></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$close</code></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$read</code></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$write</code></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$destroy</code></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$gc</code></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$create_sid</code><span class="initializer"> = ?</span></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$validate_sid</code><span class="initializer"> = ?</span></span>,<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="methodparam"><span class="type"><a href="language.types.callable.php" class="type callable">callable</a></span> <code class="parameter">$update_timestamp</code><span class="initializer"> = ?</span></span><br>): <span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span></div>

  <p class="para rdfs-comment">
   可以使用下面的方式来注册自定义会话存储函数：
  </p>
  <div class="methodsynopsis dc-description"><span class="methodname"><strong>session_set_save_handler</strong></span>(<span class="methodparam"><span class="type"><a href="language.types.object.php" class="type object">object</a></span> <code class="parameter">$sessionhandler</code></span>, <span class="methodparam"><span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span> <code class="parameter">$register_shutdown</code><span class="initializer"> = <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong></span></span>): <span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span></div>

  <p class="para rdfs-comment">
   <span class="function"><strong>session_set_save_handler()</strong></span> 设置用户自定义
   会话存储函数。
   如果想使用 PHP 内置的会话存储机制之外的方式，
   可以使用本函数。
   例如，可以自定义会话存储函数来将会话数据存储到数据库。
  </p>
 </div>


 <div class="refsect1 parameters" id="refsect1-function.session-set-save-handler-parameters">
  <h3 class="title">参数</h3>
  <p class="para">
   本函数有 2 种原型：
   <dl>
    
     <dt><code class="parameter">sessionhandler</code></dt>
     <dd>
      <p class="para">
       实现了
       <span class="interfacename"><a href="class.sessionhandlerinterface.php" class="interfacename">SessionHandlerInterface</a></span>，
       <span class="interfacename"><a href="class.sessionidinterface.php" class="interfacename">SessionIdInterface</a></span>（可选） 和/或
       <span class="interfacename"><a href="class.sessionupdatetimestamphandlerinterface.php" class="interfacename">SessionUpdateTimestampHandlerInterface</a></span>
       接口的对象，
       例如 <span class="classname"><a href="class.sessionhandler.php" class="classname">SessionHandler</a></span>。
      </p>
     </dd>
    
    
     <dt><code class="parameter">register_shutdown</code></dt>
     <dd>
      <p class="para">
       将函数 <span class="function"><a href="function.session-write-close.php" class="function">session_write_close()</a></span> 注册为
       <span class="function"><a href="function.register-shutdown-function.php" class="function">register_shutdown_function()</a></span> 函数。
      </p>
     </dd>
    
   </dl>

   或者

   <dl>
    
     <dt><code class="parameter">open(string $savePath, string $sessionName)</code></dt>
     <dd>
      <p class="para">
       实现了以下签名的 callable 回调：
       <div class="methodsynopsis dc-description"><span class="methodname"><span class="replaceable">open</span></span>(<span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$savePath</code></span>, <span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$sessionName</code></span>): <span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span></div>

      </p>
      <p class="para">
       open 回调函数类似于类的构造函数，
       在会话打开的时候会被调用。
       这是自动开始会话或者通过调用 <span class="function"><a href="function.session-start.php" class="function">session_start()</a></span> 手动开始会话
       之后第一个被调用的回调函数。
       此回调函数操作成功返回 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong>，反之返回 <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>。
      </p>
     </dd>
    
    
     <dt><code class="parameter">close</code></dt>
     <dd>
      <p class="para">
       close 回调函数类似于类的析构函数。
       在 write 回调函数调用之后调用。
       当调用 <span class="function"><a href="function.session-write-close.php" class="function">session_write_close()</a></span> 函数之后，也会调用 close 回调函数。
       此回调函数操作成功返回 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong>，反之返回 <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>。
      </p>
     </dd>
    
    
     <dt><code class="parameter">read</code></dt>
     <dd>
      <p class="para">
       实现了以下签名的 callable 回调：
       <div class="methodsynopsis dc-description"><span class="methodname"><span class="replaceable">read</span></span>(<span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$sessionId</code></span>): <span class="type"><a href="language.types.string.php" class="type string">string</a></span></div>

      </p>
      <p class="para">
       如果会话中有数据，read 回调函数必须返回将会话数据编码（序列化）后的字符串。
       如果会话中没有数据，read 回调函数返回空字符串。
      </p>
      <p class="para">
       在自动开始会话或者通过调用
       <span class="function"><a href="function.session-start.php" class="function">session_start()</a></span> 函数手动开始会话之后，PHP 内部调用 read 回调函数来获取会话数据。
       在调用 read 之前，PHP 会调用 open 回调函数。
      </p>
      <p class="para">
       read 回调返回的序列化之后的字符串格式必须与 <code class="parameter">write</code> 回调函数保存数据时的格式完全一致。
       PHP 会自动反序列化返回的字符串并填充 <var class="varname"><a href="reserved.variables.session.php" class="classname">$_SESSION</a></var> 超级全局变量。
       虽然数据看起来和 <span class="function"><a href="function.serialize.php" class="function">serialize()</a></span> 函数很相似，
       但是需要提醒的是，它们是不同的。
       请参考： <a href="session.configuration.php#ini.session.serialize-handler" class="link">session.serialize_handler</a>。
      </p>
     </dd>
    
    
     <dt><code class="parameter">write</code></dt>
     <dd>
      <p class="para">
       实现了以下签名的 callable 回调：
       <div class="methodsynopsis dc-description"><span class="methodname"><span class="replaceable">write</span></span>(<span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$sessionId</code></span>, <span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$data</code></span>): <span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span></div>

      </p>
      <p class="para">
       在会话保存数据时会调用 <code class="parameter">write</code> 回调函数。
       此回调函数接收当前会话 ID 以及 <var class="varname"><a href="reserved.variables.session.php" class="classname">$_SESSION</a></var> 中数据序列化之后的字符串作为参数。
       序列化会话数据的过程由 PHP 根据 <a href="session.configuration.php#ini.session.serialize-handler" class="link">session.serialize_handler</a> 设定值来完成。
      </p>
      <p class="para">
       序列化后的数据将和会话 ID 关联在一起进行保存。
       当调用 <code class="parameter">read</code> 回调函数获取数据时，所返回的数据必须要和
       传入 <code class="parameter">write</code> 回调函数的数据完全保持一致。
      </p>
      <p class="para">
       PHP 会在脚本执行完毕或调用 <span class="function"><a href="function.session-write-close.php" class="function">session_write_close()</a></span> 函数之后调用此回调函数。
       注意，在调用完此回调函数之后，PHP 内部会调用 <code class="parameter">close</code> 回调函数。
       <blockquote class="note"><p><strong class="note">注意</strong>: 
        <p class="para">
         PHP 会在输出流写入完毕并且关闭之后
         才调用 write 回调函数，
         所以在 write 回调函数中的调试信息不会输出到浏览器中。
         如果需要在 write 回调函数中使用调试输出，
         建议将调试输出写入到文件。
        </p>
       </p></blockquote>
      </p>
     </dd>
    
    
     <dt><code class="parameter">destroy</code></dt>
     <dd>
      <p class="para">
       实现了以下签名的 callable 回调：
       <div class="methodsynopsis dc-description">
        <span class="methodname"><span class="replaceable">destroy</span></span>(<span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$sessionId</code></span>): <span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span></div>

      </p>
      <p class="para">
       当调用 <span class="function"><a href="function.session-destroy.php" class="function">session_destroy()</a></span> 函数，
       或者调用  <span class="function"><a href="function.session-regenerate-id.php" class="function">session_regenerate_id()</a></span> 函数并且设置 destroy 参数为 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong> 时，
       会调用此回调函数。此回调函数操作成功返回 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong>，反之返回 <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>。
      </p>
     </dd>
    
    
     <dt><code class="parameter">gc</code></dt>
     <dd>
      <p class="para">
       实现了以下签名的 callable 回调：
       <div class="methodsynopsis dc-description"><span class="methodname"><span class="replaceable">gc</span></span>(<span class="methodparam"><span class="type"><a href="language.types.integer.php" class="type int">int</a></span> <code class="parameter">$lifetime</code></span>): <span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span></div>

      </p>
      <p class="para">
       为了清理会话中的旧数据，PHP 会不时的调用垃圾收集回调函数。
       调用周期由 <a href="session.configuration.php#ini.session.gc-probability" class="link">session.gc_probability</a> 
       和 <a href="session.configuration.php#ini.session.gc-divisor" class="link">session.gc_divisor</a> 参数控制。
       传入到此回调函数的 lifetime 参数由 <a href="session.configuration.php#ini.session.gc-maxlifetime" class="link">session.gc_maxlifetime</a> 设置。
       此回调函数操作成功返回 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong>，反之返回 <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>。
      </p>
     </dd>
       
    
     <dt><code class="parameter">create_sid</code></dt>
     <dd>
      <p class="para">
       实现了以下签名的 callable 回调：
       <div class="methodsynopsis dc-description"><span class="methodname"><span class="replaceable">create_sid</span></span>(): <span class="type"><a href="language.types.string.php" class="type string">string</a></span></div>

      </p>
      <p class="para">
       需要新的会话 ID 时，执行此回调函数。
       它被调用时不会传入参数，其返回值应该是一个字符串格式的、有效的 session ID。
      </p>
     </dd>
    
    
     <dt><code class="parameter">validate_sid</code></dt>
     <dd>
      <p class="para">
       实现了以下签名的 callable 回调：
       <div class="methodsynopsis dc-description"><span class="methodname"><span class="replaceable">validate_sid</span></span>(<span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$key</code></span>): <span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span></div>

      </p>
      <p class="para">
       开启 <a href="session.configuration.php#ini.session.use-strict-mode" class="link">session.use_strict_mode</a> 后，
       当启动一个 session 时，提供了 session ID 后会执行此回调。
       参数 <code class="parameter">key</code> 是待验证的 session ID。
       如果该 ID 的 session 已经存在，则为有效 session ID。
       成功时返回值应当为 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong>，失败时为 <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>。
      </p>
     </dd>
    
    
     <dt><code class="parameter">update_timestamp</code></dt>
     <dd>
      <p class="para">
       实现了以下签名的 callable 回调：
       <div class="methodsynopsis dc-description"><span class="methodname"><span class="replaceable">update_timestamp</span></span>(<span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$key</code></span>, <span class="methodparam"><span class="type"><a href="language.types.string.php" class="type string">string</a></span> <code class="parameter">$val</code></span>): <span class="type"><a href="language.types.boolean.php" class="type bool">bool</a></span></div>

      </p>
      <p class="para">
       更新 session 时执行此回调。
       参数 <code class="parameter">key</code> 是 session ID；参数 <code class="parameter">val</code> 是 session 的数据。
       成功时返回值应当为 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong>，失败时为 <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>。
      </p>
     </dd>
    
   </dl>
  </p>
 </div>


 <div class="refsect1 returnvalues" id="refsect1-function.session-set-save-handler-returnvalues">
  <h3 class="title">返回值</h3>
  <p class="para">
   成功时返回 <strong><code><a href="reserved.constants.php#constant.true">true</a></code></strong>， 或者在失败时返回 <strong><code><a href="reserved.constants.php#constant.false">false</a></code></strong>。
  </p>
 </div>


 <div class="refsect1 examples" id="refsect1-function.session-set-save-handler-examples">
  <h3 class="title">示例</h3>
  <p class="para">
   <div class="example" id="example-1">
    <p><strong>示例 #1 
     自定义会话处理程序：完整代码请参见 <span class="classname"><a href="class.sessionhandlerinterface.php" class="classname">SessionHandlerInterface</a></span>。
    </strong></p>
    <div class="example-contents"><p>
     这里仅列出了调用方式，完整代码请参见 <span class="classname"><a href="class.sessionhandlerinterface.php" class="classname">SessionHandlerInterface</a></span>。
    </p></div>
    <div class="example-contents"><p>
     这里使用了 <span class="function"><strong>session_set_save_handler()</strong></span> 函数的 OOP 原型
     并且使用第二个参数来注册 shutdown 函数。
     当将对象注册为会话保存处理程序时，建议使用这种方式。
    </p></div>
    <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /></span><span style="color: #007700">class </span><span style="color: #0000BB">MySessionHandler </span><span style="color: #007700">implements </span><span style="color: #0000BB">SessionHandlerInterface<br /></span><span style="color: #007700">{<br />    </span><span style="color: #FF8000">// 在这里实现接口<br /></span><span style="color: #007700">}<br /><br /></span><span style="color: #0000BB">$handler </span><span style="color: #007700">= new </span><span style="color: #0000BB">MySessionHandler</span><span style="color: #007700">();<br /></span><span style="color: #0000BB">session_set_save_handler</span><span style="color: #007700">(</span><span style="color: #0000BB">$handler</span><span style="color: #007700">, </span><span style="color: #0000BB">true</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">session_start</span><span style="color: #007700">();<br /><br /></span><span style="color: #FF8000">// 现在可以使用 $_SESSION 保存以及获取数据了</span></span></code></div>
    </div>

   </div>
  </p>
 </div>


 <div class="refsect1 notes" id="refsect1-function.session-set-save-handler-notes">
  <h3 class="title">注释</h3>
  <div class="warning"><strong class="warning">警告</strong>
   <p class="para">
    在对象销毁之后才会调用
    <code class="parameter">write</code> 和 <code class="parameter">close</code> 回调函数，
    所以，在这两个回调函数中不可以使用对象，也不可以抛出异常。
    如果在函数中抛出异常，PHP 既不会捕获它，也不会跟踪它，
    这样会导致程序异常终止。
    但是对象析构函数可以使用会话。
   </p>
   <p class="para">
    可以在析构函数中调用  <span class="function"><a href="function.session-write-close.php" class="function">session_write_close()</a></span>  
    函数来解决这个问题。
    但是注册 shutdown 回调函数才是更加可靠的做法。
   </p>
  </div>
  <div class="warning"><strong class="warning">警告</strong>
   <p class="para">
    如果会话在脚本结束后关闭，对于某些 SAPI 而言，当前工作目录可能已经被改变。
    可以调用 <span class="function"><a href="function.session-write-close.php" class="function">session_write_close()</a></span> 
    函数在脚本执行结束之前关闭会话。
   </p>
  </div>
 </div>

 <div class="refsect1 seealso" id="refsect1-function.session-set-save-handler-seealso">
  <h3 class="title">参见</h3>
  <p class="para">
   <ul class="simplelist">
    <li>
     <a href="session.configuration.php#ini.session.save-handler" class="link">session.save_handler</a>
     配置指示
    </li>
    <li>
     <a href="session.configuration.php#ini.session.serialize-handler" class="link">session.serialize_handler</a>
     配置指示
    </li>
    <li><span class="function"><a href="function.register-shutdown-function.php" class="function" rel="rdfs-seeAlso">register_shutdown_function()</a> - 注册在关闭时执行的函数</span></li>
    <li><span class="function"><a href="function.session-register-shutdown.php" class="function" rel="rdfs-seeAlso">session_register_shutdown()</a> - 关闭会话</span></li>
    <li>
     完整的实现请参考 
     <a href="https://github.com/php/php-src/blob/master/ext/session/tests/save_handler.inc" class="link external">&raquo;&nbsp;save_handler.inc</a>。
    </li>
   </ul>
  </p>
 </div>


</div><?php manual_footer($setup); ?>