PHP魔术方法的使用__sleep和__wakeup资源值对象图闭 包

2022-08-30 11:20:49

和 魔术方法在 PHP 中的用途是什么?我阅读了PHP文档,但仍然不清楚:__sleep__wakeup

class sleepWakeup {

    public function __construct() {
        // constructor //
    }

    public function __sleep() {
        echo 'Time to sleep.';
    }

    public function __wakeup() {
        echo 'Time to wakeup.';
    }

}

$ob = new sleepWakeup();

// call __sleep method
echo $ob->__sleep();

echo "\n";

// call __wakeup method
echo $ob->__wakeup();

此示例代码打印:

Time to sleep.
Time to wakeup.

如果我要重命名和到,然后它会做同样的事情。这两种方法的正确用法是什么?__sleep__wakeupfoobar


答案 1

如前所述,__sleep()序列化对象() 对象时调用,并在取消序列化() 对象后__wakeup()。

序列化用于持久化对象:您将获得对象作为字符串的表示形式,然后可以将其存储在,数据库,Cookie或所需的任何位置。$_SESSION

资源值

但是,不能序列化(即转换为文本表示形式)资源类型的值。这就是为什么所有这些值在完成后都会丢失的原因。serialize()unserialize()

对象图

或成员,以及成员的成员和...无限期

另一个,也许更重要的一点是,这将遍历整个对象图,如果你序列化它。当您需要它时,这很好,但是如果您只需要对象的一部分,并且某些链接对象是“特定于运行时的”,并且可以在很多对象之间共享,也可以由其他对象共享,则您可能不希望出现该行为。serialize()$obj

PHP 正确处理循环图!含义:如果(成员)$a指向$b的链接,并且$b指向$a的链接无论深度多少级,都会得到正确处理。

示例 - 会话特定的(共享)对象

例如,一个对象被 引用,但也被其他对象引用。在 ing 之后,您将希望成为下一个会话中所有其他对象具有的相同对象,而不是数据库对象的独立实例。$database$obj->db$obj->dbunserialize()

在这种情况下,您将拥有如下方法:__sleep()

/**
/* DB instance will be replaced with the one from the current session once unserialized()
 */
public function __sleep() {
    unset($this->db);
}

然后像这样恢复它:

public function __wakeup() {
    $this->db = <acquire this session's db object>
}

另一种可能性是,该对象是需要注册的某个(全局)数据结构的一部分。当然,您可以手动执行此操作:

$obj = unserialize($serialized_obj);
Thing::register($obj);

但是,如果它是对象协定的一部分,它需要位于该注册表中,则将此神奇调用留给对象的用户不是一个好主意。理想的解决方案是,如果对象关心它的责任,即在 中注册。这就是允许你透明地对你的客户做的事情(即他不再需要担心这种神奇的依赖性)。Thing__wakeup()

同样,如果合适,您可以使用“取消注册”对象。(对象在序列化时不会被销毁,但它在您的上下文中可能有意义。__sleep()

闭 包

最后但并非最不重要的一点是,闭包也不支持序列化。这意味着您必须在 中重新创建所有附加的闭包。__wakeup()


答案 2

它们很像钩子函数,我们可以根据需要使用它们。我想出了这个简单的实时示例。现在,请尝试在两种情况下执行此代码:

class demoSleepWakeup {
    public $resourceM;
    public $arrayM;

    public function __construct() {
        $this->resourceM = fopen("demo.txt", "w");
        $this->arrayM = array(1, 2, 3, 4); // Enter code here
    }

    public function __sleep() {
        return array('arrayM');
    }

    public function __wakeup() {
        $this->resourceM = fopen("demo.txt", "w");
    }
}

$obj = new demoSleepWakeup();
$serializedStr = serialize($obj);
var_dump($obj);
var_dump($serializedStr);
var_dump(unserialize($serializedStr));

方案 1:

首先通过注释和方法,检查输出。取消序列化资源时,您会发现缺少该资源。__sleep()__wakeup()

方案 2:

现在尝试运行它取消注释它们,您会发现第一个和最后一个转储的对象是相同的。var_dump


推荐