5

UnexpectedValueExceptionが投入されるのはなぜsession_start()ですか?

のプロパティを持つオブジェクトがありますSPLObjectstorage。そのオブジェクトは次のようなセッションに割り当てられます

$_SESSION['foo'] = $barObject;

内部セッションのシリアル化に直面している問題をデコードすると思われます。セッションをデータベースに保存すると、シリアル化しているように見えますが、objectStorageデコードできません。

サンプル セッション データ

self|O:4:"User":8:{s:5:"�*�id";N;s:7:"�*�nick";N;s:13:"�*�reputation";i:1;s:11:"�*�password";N;s:8:"�*�email";N;s:7:"�*�crud";O:10:"CRUDobject":2:{s:13:"�*�fieldCache";a:0:{}s:13:"�*�dependency";r:1;}s:7:"�*�auth";N;s:11:"�*�roleList";C:11:"RoleStorage":23:{x:i:1;N;,r:13;;m:a:0:{}}}

Rolestorage上記の文字列の拡張もアイデアSPLObjectstorage session_decode()を返しますか?false

属性を削除すると、roleList適切にシリアル化されます。

別々にしたら

$sr = serialize($roles); // $roles is RoleStorage object
var_dump($sr);
var_dump(unserialize($sr));

シリアルstring 'C:11:"RoleStorage":22:{x:i:1;N;,r:3;;m:a:0:{}}' (length=46)化解除中に同じメッセージが表示されて失敗します。なぜこれが起こっているのかわかりません。

注: オブジェクトをRoleStorageにアタッチする際に、オブジェクト自体をデータとして使用しました。参照として保存されていることを意味します。serialize()(if) がこれを内部的に処理する方法がわかりません。

4

3 に答える 3

3

名前の付いたオブジェクトは、RoleStorage私にとっていくつかのフラグを立てます。多くの場合、このオブジェクトにはある種のリソース、または組み込みの PHP オブジェクトへの参照が含まれています。リソースをシリアライズすることはできません。また、一部の PHP 組み込み型をシリアライズすることもできません。そのような場合は、マジック__sleep__wakeupメソッドの実装を検討してください。オブジェクトのどこかに参照
があるとすると、これらの魔法のプロパティは次のようになります。PDORoleStorage

public function __sleep()
{
    $this->pdo->commit();//commit && close
    $this->pdo = array($dsn, $user, $pwd, array(
                                              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
                                          )
    );
    return serialize($this);
}
public function __wakeup()
{
    $this->pdo = new PDO($this->pdo[0], $this->pdo[1], $this->pdo[2], $this->pdo[3]);
}

しかし、RoleStorageオブジェクトが の子であると言っているので、 のインターフェイスの実装をSPLObjectStorageオーバーライドしたほうがよいでしょう。SPLObjectStorageSerializable

__sleep() が親クラスのプライベート プロパティの名前を返すことはできません。これを行うと、E_NOTICE レベルのエラーが発生します。代わりに、Serializable インターフェイスを使用できます。

子クラスのserializeメソッドですべてのプロパティを反復処理することを宣言し、そのデータを配列に格納することをお勧めします。シリアル化された配列を返し、その文字列をシリアル化解除してunserializeメソッドに戻し、ループ内のすべてのプロパティを再割り当てします。
プライベート プロパティがある場合SPLObjectStorageは、次のように取得できます。

class RoleStorage extends SPLObjectStorage
      implements Serializable
{
    public function serialize()
    {
        return serialize((array) $this);
    }
    public function unserialize($string)
    {
        $array = unserialize($string);
        foreach($array as $property => $value)
        {
            $property = explode("\0", $property);//private & protected properties
            $this->{end($property)} = $value;
        }
    }
}

の詳細については、マニュアルexplode("\0",$property);を参照するか、この質問を確認してください

于 2013-08-09T12:48:25.157 に答える
2

なぜこれが起こっているのか分かりません

PHP バージョンと具体的なスクリプトSPLObjectStorageでは、独自のシリアル化を処理しない限り、に基づいてオブジェクトをシリアル化することはできません。シリアル化された文字列のこの部分が表示された場合:

C:11:"RoleStorage":23:{x:i:1;N;,r:13;;m:a:0:{}}

これはRoleStorageオブジェクトを表します。先頭の大きな C は次の略です

C -シリアライズ可能なインターフェイスを実装するオブジェクト

したがって、ここではオブジェクト自体がシリアライゼーションとアンシリアライゼーションについて責任を負います。通常はこれが機能すると予想できますが、すべてのソフトウェアにバグがないわけではありません。

あなたの場合、PHPが間違いを犯したようです。ここでの内部形式は次のとおりです。

x:i:1;N;,r:13;;m:a:0:{} 
      ^^^^^^^

問題は強調表示された位置にあります。これには、NULL ではなく、シリアル化されたオブジェクトが必要です。また、参照 ( here ) でコンマで終了するのでr:13はなく、 null ( N) を使用して動作します。

したがって、以前のオブジェクトを参照することによって引き起こされるヒックアップのように見えます (この参照は、ユーザーランド PHP の参照/変数エイリアスと同じではないことに注意してください)。

では、どうやって行くのですか?

問題を切り分けて、自己完結型の再現可能な例を作成する時が来ました。これは、問題をさらに詳しく調べるために必要です。これは、次の 2 つの理由から重要です。

  1. これが PHP のバグである場合は、報告し、回帰テストを作成して PHP Q&A に追加し、バグを修正する必要があります (まだ修正されていない場合)。
  2. 回避策を探している場合、迅速かつ簡単に回避策を作成するには、元の問題を再現する必要があります。

回避策としていくつかのテストを実行しましたが、これまでのところ問題を再現できていないため、問題を回避する方法を実際に提案することはできません。

于 2013-08-13T22:33:24.723 に答える
1

これに似た問題に関して、最近クローズされたバグがあります。実行している php のバージョンによっては、影響を受ける可能性があります。影響を受けるバージョンは 5.3.15 です。

抜粋:

[2012-07-27 16:08 UTC] j dot henge-ernst at interexa dot de

問題は、ArrayIterator (および場合によっては ArrayObject または他の SPL クラス) のシリアル化解除がオブジェクト参照を逆参照できないことです。

このバグの影響を受けている場合は、逆参照に関連している可能性があります。おそらく、新しいバージョンの PHP を試して、まだ発生するかどうかを確認してください。

于 2013-08-08T13:34:27.710 に答える