【PHP】セッションを跨いでオブジェクトを使う

phpでプログラムを書いていると、セッション間でデータを扱う機会はよくあります。
セッションの使い方で良くあるのは、文字列数字を代入する方法です。

では、それ以外の情報は受け渡せないのでしょうか?

さて、
今回はセッションにオブジェクトを渡す方法について記載します。

公式ドキュメント

www.php.net

オブジェクトを分解してセッションに渡す

形式が決まった複数の属性を持つ値を扱いたい場合、クラスを用意してオブジェクトにまとめる方法があります。
例えばユーザー情報をオブジェクトにすると次のような書き方をします。

<?php
namespace App\Http\Request;

class User {
    private $name = null;
    private $age = null;

    // setter
    public function setName ($value) {
        $this->name = $value;
    }
    public function setAge ($value) {
        $this->age = $value;
    }

    // getter
    public function getName() {
        return $this->name;
    }
    public function getAgeE() {
        return $this->age;
    }
}

$user =  new User();
$user->setName('bob');
$user->setAge(20);

この情報を別のページでも使いたい場合は、$_SESSION に代入します。
しかし、オブジェクトはそのまま代入する事はできません。
(代入するとどうなるかは次の項で解説します。 )

そのため、 次のようにオブジェクトを分解してセッションに代入し、別セッションで新しくオブジェクトを作り直します。

前セッション

<?php
$user =  new User();
$user->setName('bob');
$user->setAge(20);

session_start();

// オブジェクトからセッションに直接値を代入。  
$_SESSION['user_name'] = $user->getName;
$_SESSION['user_age'] = $user->getAge;

別セッション

<?php
session_start();

// オブジェクトを作り直す
$user =  new User();
$user->setName($_SESSION['user_name']);
$user->setAge($_SESSION['user_age']);

これでは、冗長的な管理方法になってしまいます。
情報の項目が多くなったり、受け渡すユーザーがくなればそれだけ処理も長くなります。

オブジェクトを直接渡せればこういった煩わしさはありません。

オブジェクトを直接セッションに渡す

オブジェクトを正常に渡せない例

実は、実際にオブジェクトをそのままセッションに渡す事はできます。

<?php
$user =  new User();
$user->setName('bob');
$user->setAge(20);

session_start();
$_SESSION['user'] = $user;

別のセッションで取得したオブジェクトからクラスで定義した関数を実行します。

<?php
session_start();
$user = $_SESSION['user']

echo($user->getName());
// Error

しかし、次のようなエラーが出てしまいます。

Fatal error: (呼び出し元関数): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition &quot; App\Http\Request\User&quot; of the object you are trying to operate on was loaded before unserialize() gets called or provide a __autoload() function to load the class definition in (呼び出し元)

セッションから取得したオブジェクトはどうなっているのか?

実際に取得したデータを見ると次のようなデータ形式になっています

object(__PHP_Incomplete_Class)#1 (3) {
  ["__PHP_Incomplete_Class_Name"]=>
  string(21) "App\Http\Request\User"
  ["name":"App\User":private]=>
  string(3) "bob"
  ["age":"App\Http\Request\User":private]=>
  int(20)
}

オブジェクトとして解析できていますが、不完全なクラス(__PHP_Incomplete_Class )だという事ははわかります。

オブジェクトのシリアライズ

冒頭で書きましたが、セッションには文字列を導入する事ができます。
前述の方法は、オブジェクトの書き方をした文字列をセッションに代入しただけです。

それなら、解析できる共通の形式で渡せばいいのです。
(wikipediaから言葉をお借りますが、)階層をもたないフラットな(直線的な)データ構造に変換する事をシリアライズと言います。

ja.wikipedia.org

オブジェクトをシリアライズしてセッションに代入

phpでオブジェクトをシリアライズするための関数が用意されています。
関数名はserialize を使用します。

www.php.net

オブジェクトを、次のようにシリアライズしてセッションに代入します。

<?php
$user =  new User();
$user->setName('bob');
$user->setAge(20);

session_start();

// シリアライズしたオブジェクトを変数に代入
$_SESSION['user'] = serialize($user);
シリアライズされたオブジェクトの中身

シリアライズすると、下記のように変換されます。
これは、バイトストリームと呼ばれる形式です。

<?php
echo(serialize($user));
// O:21:"App\Http\Request\User":2:{s:27:"App\Http\Request\Username";s:3:"bob";s:26:"App\Http\Request\Userage";i:20;}

シリアライズされたオブジェクトを復元

別のセッションに移って、セッションからシリアライズされたオブジェクトを取得します。
そのままではオブジェクトと認識できないので、アンシリアライズしてオブジェクトを復元します。

シリアライズを戻すにはunserializeを使用します。

www.php.net

次のように処理する事で、復元することが出来ます。  

session_start();
$user = $_SESSION['user']

echo($user->getName());
// bob

これでセッションを跨いだオブジェクトの受け渡しをする事ができます。



以上です。

フレームワークだとシリアライズの処理を内包している場合があります。
そのため、プレーンなphpで書く場合つまづきやすい箇所です。
この方法を知っていると実現できる事が増えるのではないでしょうか?

なお、今回はオブジェクトを題材にしましたが、配列でも同じ事が出来ます。
セッションに配列を代入すること自体は珍しいことではありませんので、配列をシリアライズしてセッションに代入する機会はないかもしれません。
ご参考までに。

©︎2017-2018 WebSandBag