douxu4610 2013-02-13 17:18
浏览 58
已采纳

PHP - 使用静态属性序列化类

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!
  • 写回答

2条回答 默认 最新

  • duanlachu7344 2013-02-13 17:30
    关注

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?