php PHP魔术方法__sleep和__wakeup的使用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11630341/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Use of PHP Magic Methods __sleep and __wakeup
提问by Madan Sapkota
What is the use of the __sleepand __wakeupmagic methods in PHP? I read the PHP documentation but it's still not clear:
PHP中的the__sleep和__wakeupmagic方法有什么用?我阅读了 PHP 文档,但仍然不清楚:
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();
This sample code prints:
此示例代码打印:
Time to sleep.
Time to wakeup.
If I were to rename __sleepand __wakeupto fooand barthen it does the same thing. What is the proper use of these two methods?
如果我要重命名__sleep并__wakeup以foo和bar然后做同样的事情。这两种方法的正确用法是什么?
回答by phant0m
As already described, __sleep()is called when you serialize()an object and __wakeup()after you unserialize()it.
如前所述,__sleep()当你serialize()是一个对象时和__wakeup()你之后调用unserialize()它。
Serialization is used to persist objects: You will get a representation of an object as a string that can then be stored in $_SESSION, a database, cookies or anywhere else you desire.
序列化用于持久化对象:您将获得作为字符串的对象表示,然后可以将其存储在$_SESSION、数据库、cookies 或您想要的任何其他地方。
Resource values
资源价值
However, serialize()cannotserialize (i.e. transform into a textual representation) value sof the resource type. This is why all of these values will go missing after unserialize()ing it.
但是,serialize()无法序列化(即转换为文本表示)资源类型的值。这就是为什么所有这些值在unserialize()ing之后都会丢失的原因。
Object graph
对象图
or members, and the member's members and the ... ad infinitum
或成员,以及成员的成员和……无止境
Another, perhaps more important point is, that serialize()will traverse the entire object graph of $objif you serialize it. This is great when you need it, but if you only need parts of the object and certain linked objects are "runtime-specific" and shared across a lot of objects but also by other objects, you may not want that behavior.
另一个可能更重要的一点是,如果序列化它,serialize()它将遍历整个对象图$obj。这在您需要时非常有用,但是如果您只需要对象的一部分,并且某些链接对象是“运行时特定的”并且在许多对象之间共享,但也由其他对象共享,您可能不希望这种行为。
PHP handles cyclic graphs correctly! Meaning: If (a member of) $a links to $b, and $b links to $a is handled correctly however many levels deep.
PHP 正确处理循环图!含义:如果(的成员)$a 链接到 $b,并且 $b 到 $a 的链接被正确处理,无论深度多少。
Example - session specific (shared) objects
示例 - 会话特定(共享)对象
For instance, a $databaseobject is referenced by $obj->db, but also by other objects. You will want $obj->dbto be the same objects - after unserialize()ing - that all the other objects in your next session have, not an isolated instance of the database object.
例如,一个$database对象被 引用$obj->db,但也被其他对象引用。您将希望$obj->db成为unserialize()下一个会话中所有其他对象所拥有的相同对象 - 在ing之后,而不是数据库对象的孤立实例。
In this case, you would have __sleep()method such as this:
在这种情况下,您将拥有如下__sleep()方法:
/**
/* DB instance will be replaced with the one from the current session once unserialized()
*/
public function __sleep() {
unset($this->db);
}
and then restore it like this:
然后像这样恢复它:
public function __wakeup() {
$this->db = <acquire this session's db object>
}
Another possibility is, that the object is part of some (global) datastructure where it needs to be registered. You could do this manually of course:
另一种可能性是,该对象是需要注册的某些(全局)数据结构的一部分。您当然可以手动执行此操作:
$obj = unserialize($serialized_obj);
Thing::register($obj);
However, if it is part of the objects contract that it needs to be in that registry, it's not a good idea to leave this magical call up to the user of your object. The ideal solution is, if the object cares about it's responsibilities, i.e. being registered in Thing. That's what __wakeup()allows you to do transparently (i.e. he need no longer worry about that magical dependency) to your client.
但是,如果它是需要在该注册表中的对象契约的一部分,那么将这个神奇的调用留给对象的用户并不是一个好主意。理想的解决方案是,如果对象关心它的职责,即在Thing. 这就是__wakeup()允许你对你的客户透明地做的事情(即他不再需要担心那种神奇的依赖)。
Similarly, you could use __sleep()to "un-register" an object if appropriate. (Objects are not destroyed when they're serialized, but it may make sense in your context.)
同样,__sleep()如果合适,您可以使用“取消注册”对象。(对象在序列化时不会被销毁,但在您的上下文中可能有意义。)
Closures
关闭
Last but not least, closures do notsupport serialization either. This means that you will have to re-create all attached closures in __wakeup().
最后但并非最不重要的一点是,闭包也不支持序列化。这意味着您必须在__wakeup().
回答by Mohammed Asad
They are pretty much like hook functions, which we can use according to our needs. I came up with this simple real time example. Now try executing this code in two scenarios:
它们很像钩子函数,我们可以根据需要使用它们。我想出了这个简单的实时示例。现在尝试在两种情况下执行此代码:
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));
Scenario 1:
场景一:
First by commenting __sleep()and __wakeup()methods, check the output. You will find the resource missing when you unserialize it.
首先通过注释__sleep()和__wakeup()方法,检查输出。反序列化时会发现资源丢失。
Scenario 2:
场景2:
Now try running it uncommenting them, you will figure out that the object dumped in first and last var_dumpwould be same.
现在尝试运行它取消注释它们,您会发现第一个和最后一个转储的对象var_dump是相同的。
回答by Louis-Philippe Huberdeau
These methods are used when calling serialize() and unserialize() on the objects to make sure you have a hook to remove some properties like database connections and set them back when loading. This happens when storing objects in sessions among other things.
在对象上调用 serialize() 和 unserialize() 时使用这些方法,以确保您有一个钩子来删除一些属性,如数据库连接,并在加载时将它们设置回来。在会话中存储对象时会发生这种情况。
回答by donald123
try out this
试试这个
<?php
$ob = new sleepWakeup();
$safe_me = serialize($ob);
$ob = unserialize($safe_me);
?>
回答by DevWL
Since PHP 7.4 there will be new methods __serialize() and __unserialize() available which should slightly change the usage of __sleep and __wakeup magic methods.
从 PHP 7.4 开始,将会有新方法 __serialize() 和 __unserialize() 可用,它们应该稍微改变 __sleep 和 __wakeup 魔术方法的用法。
PHP currently provides two mechanisms for custom serialization of objects: The __sleep()/__wakeup() magic methods, as well as the Serializable interface. Unfortunately, both approaches have issues that will be discussed in the following. This RFC proposes to add a new custom serialization mechanism that avoids these problems.
PHP 目前提供了两种自定义对象序列化机制:__sleep()/__wakeup() 魔术方法,以及 Serializable 接口。不幸的是,这两种方法都有将在下面讨论的问题。该 RFC 建议添加一个新的自定义序列化机制来避免这些问题。
More in PHP RFC manual https://wiki.php.net/rfc/custom_object_serialization.
更多 PHP RFC 手册https://wiki.php.net/rfc/custom_object_serialization。
// Returns array containing all the necessary state of the object.
public function __serialize(): array;
// Restores the object state from the given data array.
public function __unserialize(array $data): void;
The usage is very similar to the Serializable interface. From a practical perspective the main difference is that instead of calling serialize() inside Serializable::serialize(), you directly return the data that should be serialized as an array.
用法与 Serializable 接口非常相似。从实际角度来看,主要区别在于,不是在 Serializable::serialize() 中调用 serialize(),而是直接返回应该序列化为数组的数据。
The following example illustrates how __serialize()/__unserialize() are used, and how they compose under inheritance:
下面的例子说明了 __serialize()/__unserialize() 是如何使用的,以及它们是如何在继承下组成的:
class A {
private $prop_a;
public function __serialize(): array {
return ["prop_a" => $this->prop_a];
}
public function __unserialize(array $data) {
$this->prop_a = $data["prop_a"];
}
}
class B extends A {
private $prop_b;
public function __serialize(): array {
return [
"prop_b" => $this->prop_b,
"parent_data" => parent::__serialize(),
];
}
public function __unserialize(array $data) {
parent::__unserialize($data["parent_data"]);
$this->prop_b = $data["prop_b"];
}
}
This resolves the issues with Serializable by leaving the actual serialization and unserialization to the implementation of the serializer. This means that we don't have to share the serialization state anymore, and thus avoid issues related to backreference ordering. It also allows us to delay __unserialize() calls to the end of unserialization.
这通过将实际的序列化和反序列化留给序列化器的实现来解决 Serializable 的问题。这意味着我们不必再共享序列化状态,从而避免与反向引用排序相关的问题。它还允许我们将 __unserialize() 调用延迟到反序列化结束。

