PHP - 序列化一个具有静态属性的类 [英] PHP - serialize a class with static properties

查看:112
本文介绍了PHP - 序列化一个具有静态属性的类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当用户登录我的网站时,我创建了一个 User 类的实例,获取一些用户相关数据并将对象存储在 SESSION



我从数据库中提取的一些数据在整个会话中应该是不变的,我希望数据可以从其他对象。当使用另一个对象中的值时,我喜欢使用 User :: $ static_value_in_class $ _ SESSION ['static_value_in_session']



问题是,当序列化我的 User instance into SESSION ,然后加载不同的页面。



类定义:

  class User {
public $ name;
public static $ allowed_actions;
public function __construct($ username,$ password){
//验证凭证等
self :: $ allowed_actions = get_allowed_actions_for_this_user($ this);
}
}
class Blog {
public static function write($ text){
if(in_array(USER_MAY_WRITE_BLOG,User :: $ allowed_actions)){
//写博客条目
}
}
}

login.php:

  $ user = new User($ _ POST ['username' $ _POST ['password']); 
if(successful_login($ user)){
$ _SESSION ['user'] = $ user;
header('Location:index.php');
}

index.php: b
$ b

  if(!isset($ _ SESSION ['user'])){
header('Location:login.php');
}
Blog :: write(I'm in index.php!Hooray!)
//无效,因为博客需要User :: $ allowed_actions

我应该实现 Serializable ,并写我自己的版本 serialize() unserialize()包含静态数据?



<我应该咬我的嘴唇,访问 $ _ SESSION 变量从博客类中吗?



我需要一个有效的用户实例发送到 Blog write()方法?



或者互联网有一个更好的想法...




)。



我的网站处理具有共享预算帐户的用户组。
用户可以在组同意的某些事情上花费组钱,他们通过创建 Transaction 类的实例来报告事务,并将其发送到



  class Bank {
//小组商定的花费原因
public static $ valid_transaction_reasons;
public function __construct(User $ user){
Bank :: $ valid_transaction_reasons = load_reasons_for_this_group($ user-> bank_id);
}
}

/ code> class:

  class User {
public $ bank_id;
public function __construct($ username,$ password){
$ query =SELECT bank_id FROM users WHERE username = $ username AND password = $ password;
$ result = mysql_fetch_array(mysql_query($ query));
$ this-> bank_id = $ result ['bank_id'];
}
}

/ code> class:

  class Transaction {
public function __construct $ amount){
if(!in_array($ reason,Bank :: $ valid_transaction_reasons)){
//错误!用户不能花钱在这,组不覆盖它
}
else {
//构建事务对象
}
}
}

实际代码(login.php或其他): / p>

  $ user = new User($ _ GET ['uname'],$ _GET ['pword']); 
$ _SESSION ['bank'] =新银行($ user);

//一些shit发生,用户导航到submit_transaction.php

$ trans = new Transaction(REASON_BEER,5.65);
//错误! Bank :: $ valid_transaction_reasons是空的!


解决方案

正如我在评论中提到的,软件设计问题比如何用PHP实现这个问题。



静态属性不是对象状态的一部分,因此不会被序列化。



我给你一个简单的例子,我将如何解决相关的问题。假设您有以下消息类,它有一个静态$ id属性,以确保所有实例都有唯一的ID:

 消息{

public static $ id;

public $ instanceId;

public $ text;

/ **
*
* /
public function __construct($ text){
// id将在静态var $ b if(!self :: $ id){
self :: $ id = 1;
} else {
self :: $ id ++;
}

//在当前状态下复制
$ this-> instanceId = self :: $ id;
$ this-> text = $ text;
}
}

序列化/取消序列化代码:

  $ m1 = new Message('foo'); 
printf('created message id:%s text:%s%s',
$ m1-> instanceId,$ m1-> text,PHP_EOL);
$ m2 = new Message('bar');
printf('created message id:%s text:%s%s',
$ m2-> instanceId,$ m2-> text,PHP_EOL);

$ messages = array($ m1,$ m2);

$ ser1 = serialize($ m1);
$ ser2 = serialize($ m2);

$ m1 = unserialize($ ser1);
printf('unserialized message id:%s text:%s%s',
$ m1-> instanceId,$ m1-> text,PHP_EOL);
$ m2 = unserialize($ ser2);
printf('unserialized message id:%s text:%s%s',
$ m2-> instanceId,$ m2-> text,PHP_EOL);

为了确保id在多个脚本运行中是唯一的,进一步的工作是必要的。您必须确保 Message :: $ id 在任何对象创建之前使用上次脚本运行的值进行初始化。当涉及到web服务器上的并行PHP请求时,这将额外接线。






它只是一个最简单的静态属性的例子,我知道:一个实例计数器。在这种情况下,我会这样做。但我希望你看到有进一步的工作需要序列化/ unserialize static 属性没有副作用。这取决于您的应用程序需求。



这个问题不能一般回答。我倾向于说在任何情况下,序列化静态成员都没有意义。但我很感激对此的意见。


When a user logs into my site, I create an instance of my User class, fetch some user-related data and store the object in the SESSION.

Some of the data I fetch from the database should be constant throughout the session AND I want the data to be accessible from other objects. I prefer using User::$static_value_in_class to $_SESSION['static_value_in_session'] when using the value from within another object, but I'm open to persuasion.

The problem is, the values aren't remembered when I serialize my User instance into the SESSION, then load a different page.

Class definitions:

class User {
    public $name;
    public static $allowed_actions;
    public function __construct($username, $password) {
        // Validate credentials, etc.
        self::$allowed_actions = get_allowed_actions_for_this_user($this);
    }   
}
class Blog {
    public static function write($text) {
        if (in_array(USER_MAY_WRITE_BLOG, User::$allowed_actions)) {
            // Write blog entry
        }
    }
}

login.php:

$user = new User($_POST['username'], $_POST['password']);
if (successful_login($user)) {
    $_SESSION['user'] = $user;
    header('Location: index.php');
}

index.php:

if (!isset($_SESSION['user'])) {
    header('Location: login.php');
}
Blog::write("I'm in index.php! Hooray!")
// Won't work, because Blog requires User::$allowed_actions

Should I implement Serializable and write my own version of serialize() and unserialize() to include the static data?

Should I bite my lip and access the $_SESSION variable from within the Blog class?

Should I require a valid User instance sent to the Blog write() method?

Or maybe the internets has a better idea...



EDIT: Writing my real use case (not full code, but enough to get the gist).

My site handles groups of users with shared budget accounts. Users may spend group money on certain things the group agreed upon, and they report transactions by creating instances of the Transaction class and sending it to the Bank class for database storage.

Bank class:

class Bank {
   // Group-agreed reasons to spend money
   public static $valid_transaction_reasons;
   public function __construct(User $user) {
      Bank::$valid_transaction_reasons = load_reasons_for_this_group($user->bank_id);
   }
}

User class:

class User {
   public $bank_id;
   public function __construct($username, $password) {
      $query = "SELECT bank_id FROM users WHERE username=$username AND password=$password";
      $result = mysql_fetch_array(mysql_query($query));
      $this->bank_id = $result['bank_id'];
   }
}

Transaction class:

class Transaction {
   public function __construct($reason, $amount) {
      if (!in_array($reason, Bank::$valid_transaction_reasons)) {
         // Error! Users can't spend money on this, the group doesn't cover it
      }
      else {
         // Build a Transaction object
      }
   }
}

Actual code (login.php, or something):

$user = new User($_GET['uname'], $_GET['pword']);
$_SESSION['bank'] = new Bank($user);

// Some shit happens, user navigates to submit_transaction.php

$trans = new Transaction(REASON_BEER, 5.65);
// Error! Bank::$valid_transaction_reasons is empty!

解决方案

As I mentioned in the comment, this is more a software design question than a question how to achieve this with PHP.

A static property is not part of the state of an object and will therefore not being serialized with it.

I'll give you a short example how I would solve a related problem. Imagine you have the following message class, that has a static $id property to make sure all instances have a unique id:

class Message {

    public static $id;

    public $instanceId;

    public $text;

    /**
     *
     */
    public function __construct($text) {
        // the id will incremented in a static var
        if(!self::$id) {
            self::$id = 1;
        } else {
            self::$id++;
        }

        // make a copy at current state
        $this->instanceId = self::$id; 
        $this->text = $text;
    }
}

Serialization / Unserialization code:

$m1 = new Message('foo');
printf('created message id: %s text: %s%s',
    $m1->instanceId,  $m1->text, PHP_EOL);
$m2 = new Message('bar');
printf('created message id: %s text: %s%s',
    $m2->instanceId,  $m2->text, PHP_EOL);

$messages = array($m1, $m2);

$ser1 = serialize($m1);
$ser2 = serialize($m2);

$m1 = unserialize($ser1);
printf('unserialized message id: %s text: %s%s',
    $m1->instanceId,  $m1->text, PHP_EOL);
$m2 = unserialize($ser2);
printf('unserialized message id: %s text: %s%s',
    $m2->instanceId,  $m2->text, PHP_EOL);

To make sure that the id is unique across multiple script runs further work is nessary. You'll have to make sure that Message::$id is initialized before any object creation, using the value from last script run. This will get additionally wired when it comes to parallel PHP request on a webserver.


Its just an example with the simplest static property I know: an instance counter. In this case I would do so. But I hope you see that there is further work required to serialize / unserialize static properties without have side effects. And this depends on your application needs.

This question cannot be answered general I tend to say it makes no sense in any case to serialize static members. But I would appreciate comments on this.

这篇关于PHP - 序列化一个具有静态属性的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆