“瞬时”属性在PHP类? [英] "Transient" properties in a PHP class?

查看:153
本文介绍了“瞬时”属性在PHP类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用PHP几年了,但直到现在,从来没有需要显式地处理序列化,只使用 $ _ SESSION 。现在我有一个项目需要我手动实现某些数据的序列化机制 - 我知道这个问题也适用于 $ _ SESSION 以及。

I've worked with PHP for a few years now, but up until now never had a need to deal with serialisation explicitly, only using the $_SESSION. Now I have a project that requires me to manually implement serialisation mechanism for certain data - and I realise that the issue is applicable to $_SESSION as well.

我有一个包含许多属性的类。大多数这些属性是小的(如在内存消耗):数字,相对较短的字符串等。然而,类还包含一些属性,可能包含HUGE数组(例如一个数据库表的整个转储:100,000行,每100个字段)。发生时,这是需要序列化/反序列化的类之一 - 幸运的是,包含大型数组的属性不需要序列化,因为它们本质上是临时的工作,并且根据需要重新构建。

I have a class that contains a number of properties. Most of these properties are small (as in memory consumption): numbers, relatively short strings, etc. However the class also contains some properties, which may contain HUGE arrays (e.g. an entire dump of a database table: 100,000 rows with 100 fields each). As it happens, this is one of the classes that needs to be serialised/deserialised - and, luckly, the properties containing large arrays don't need to be serialised, as they are essentially temporary pieces of work and are rebuilt anyway as necessary.

在这种情况下,在Java中,我只需声明属性为 transient - 它将从serialisaion中省略。不幸的是,PHP不支持这样的限定符。

In such circumstances in Java, I would simply declare the property as transient - and it would be omitted from serialisaion. Unfortunately, PHP doesn't support such qualifiers.

一种处理方式是它有这样的:

One way to deal with is it to have something like this:

class A implements Serializable
{
    private $var_small = 1234;
    private $var_big = array( ... );  //huge array, of course, not init in this way

    public function serialize()
    {
        $vars = get_object_vars($this);
        unset($vars['var_big']);
        return serialize($vars);
    }

    public function unserialize($data)
    {
        $vars = unserialize($data);
        foreach ($vars as $var => $value) {
            $this->$var = $value;
        }
    }
}

因为我每次添加另一个瞬态属性时需要更新 serialize 方法。此外,一旦继承发挥作用,这变得甚至更复杂 - 处理,因为瞬态属性可能在子类和父类。我知道,它仍然可行,但我更愿意委托尽可能多的语言,而不是重新发明的轮子。

However this is rather cumbersome, as I would need to update serialize method every time I add another transient property. Also, once the inheritance comes into play, this becomes even more complicated - to deal with, as transient properties may be in both subclass and the parent. I know, it's still doable, however I would prefer to delegate as much as possible to the language rather than reinvent the wheel.

因此,什么是最好的方式来处理瞬态特性?

So, what's the best way to deal with transient properties? Or am I missing something and PHP supports this out of the box?

推荐答案

Php提供 __睡眠魔法方法,它允许您选择要序列化的属性。

Php provides __sleep magic method which allows you to choose what attributes are to be serialized.

EDIT 我测试了在游戏中继承时 __ sleep() p>

EDIT I've tested how does __sleep() work when inheritance is in the game:

<?php

class A {
    private $a = 'String a';
    private $b = 'String b';

    public function __sleep() {
        echo "Sleep A\n";
        return array( 'a');
    }
}

class B extends A {
    private $c = 'String c';
    private $d = 'String d';

    public function __sleep() {
        echo "Sleep B\n";
        return array( 'c');
    }
}

class C extends A {
    private $e = 'String e';
    private $f = 'String f';

    public function __sleep() {
        echo "Sleep C\n";
        return array_merge( parent::__sleep(), array( 'e'));
    }
}

$a = new A();
$b = new B();
$c = new C();

echo serialize( $a) ."\n";  // Result: O:1:"A":1:{s:4:"Aa";s:8:"String a";}
// called "Sleep A" (correct)

echo serialize( $b) ."\n"; // Result: O:1:"B":1:{s:4:"Bc";s:8:"String c";}
// called just "Sleep B" (incorrect)

echo serialize( $c) ."\n"; // Caused: PHP Notice:  serialize(): "a" returned as member variable from __sleep() but does not exist ...

// When you declare `private $a` as `protected $a` that class C returns:
// O:1:"C":2:{s:4:"*a";s:8:"String a";s:4:"Ce";s:8:"String e";}
// which is correct and called are both: "Sleep C" and "Sleep A"

因此,只有当它声明为protected时,你才可以序列化父数据: - /

So it seems that you can serialize parent data only if it's declared as protected :-/

2 我尝试过 Serializable 与以下代码:

EDIT 2 I've tried it with Serializable interface with following code:

<?php

class A implements Serializable {
    private $a = '';
    private $b = '';

    // Just initialize strings outside default values
    public function __construct(){
        $this->a = 'String a';
        $this->b = 'String b';
    }

    public function serialize() {
        return serialize( array( 'a' => $this->a));
    }

    public function unserialize( $data){
        $array = unserialize( $data);
        $this->a = $array['a'];
    }
}

class B extends A {
    private $c = '';
    private $d = '';

    // Just initialize strings outside default values
    public function __construct(){
        $this->c = 'String c';
        $this->d = 'String d';
        parent::__construct();
    }

    public function serialize() {
        return serialize( array( 'c' => $this->c, '__parent' => parent::serialize()));
    }

    public function unserialize( $data){
        $array = unserialize( $data);
        $this->c = $array['c'];
        parent::unserialize( $array['__parent']);
    }
}

$a = new A();
$b = new B();

echo serialize( $a) ."\n";
echo serialize( $b) ."\n";

$a = unserialize( serialize( $a)); // C:1:"A":29:{a:1:{s:1:"a";s:8:"String a";}}
$b = unserialize( serialize( $b)); // C:1:"B":81:{a:2:{s:1:"c";s:8:"String c";s:8:"__parent";s:29:"a:1:{s:1:"a";s:8:"String a";}";}}


print_r( $a);
print_r( $b);

/** Results:
A Object
(
    [a:A:private] => String a
    [b:A:private] => 
)
B Object
(
    [c:B:private] => String c
    [d:B:private] => 
    [a:A:private] => String a
    [b:A:private] => 
)
*/

因此总结:可以通过 __ sleep()仅当他们没有超类中的私有成员(这需要序列化)。您可以通过实现 Serializable 接口来序列化复杂对象,但它会带来一些编程开销。

So to sum up: you can serialize classes via __sleep() only if they don't have private members in super class (which need to be serialized as well). You can serialize complex object via implementing Serializable interface, but it brings you some programming overhead.

这篇关于“瞬时”属性在PHP类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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