Mad*_*ota 36 php oop magic-methods
有什么用的__sleep,并__wakeup在PHP魔术方法?我阅读了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();
Run Code Online (Sandbox Code Playgroud)
此示例代码打印:
Time to sleep.
Time to wakeup.
Run Code Online (Sandbox Code Playgroud)
如果我重新命名__sleep,并__wakeup以foo和bar然后做同样的事情.这两种方法的正确用法是什么?
pha*_*t0m 43
如前所述,__sleep()当你serialize()是一个对象并__wakeup()在你之后调用unserialize()它.
序列化用于持久化对象:您将获得对象的表示形式,然后可以将其存储在$_SESSION数据库,数据库,cookie或任何您想要的其他地方.
但是,serialize() 无法序列化(即转换为文本表示)值资源类型.这就是为什么所有这些值在unserialize()它之后都会丢失的原因.
或成员,成员和成员......无限
另一个,也许更重要的一点是,如果你序列化它将serialize()遍历整个对象图$obj.当你需要它时,这很好,但如果你只需要对象的一部分,某些链接对象是"特定于运行时"的,并且在很多对象之间共享,但也可以由其他对象共享,你可能不需要这种行为.
PHP正确处理循环图!含义:如果(一个成员)$ a链接到$ b,并且$ b链接到$ a的处理正确,但是很多级别.
例如,$database对象$obj->db由其他对象引用,但也由其他对象引用.您将希望$obj->db成为相同的对象 - unserialize()在您之后- 您下一个会话中的所有其他对象都具有,而不是数据库对象的孤立实例.
在这种情况下,你会有这样的__sleep()方法:
/**
/* DB instance will be replaced with the one from the current session once unserialized()
*/
public function __sleep() {
unset($this->db);
}
Run Code Online (Sandbox Code Playgroud)
然后像这样恢复:
public function __wakeup() {
$this->db = <acquire this session's db object>
}
Run Code Online (Sandbox Code Playgroud)
另一种可能性是,该对象是需要注册的某些(全局)数据结构的一部分.您当然可以手动执行此操作:
$obj = unserialize($serialized_obj);
Thing::register($obj);
Run Code Online (Sandbox Code Playgroud)
但是,如果它是对象契约的一部分,它需要在该注册表中,那么将这个神奇的调用留给对象的用户并不是一个好主意.理想的解决方案是,如果对象关心它的责任,即注册Thing.这就是__wakeup()允许你透明地(即他不再需要担心那种神奇的依赖性)给你的客户做的事情.
同样,__sleep()如果合适,您可以使用"取消注册"对象.(对象在序列化时不会被销毁,但在您的上下文中可能有意义.)
最后但同样重要的是,闭包也不支持序列化.这意味着您必须重新创建所有附加的闭包__wakeup().
Moh*_*sad 11
它们非常类似于钩子功能,我们可以根据需要使用它们.我想出了这个简单的实时例子.现在尝试在两种情况下执行此代码:
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));
Run Code Online (Sandbox Code Playgroud)
场景1:
首先通过注释__sleep()和__wakeup()方法,检查输出.反序列化时,您会发现资源丢失.
场景2:
现在尝试运行它取消注释它们,你会发现在第一个和最后一个转储的对象var_dump是相同的.
在对象上调用serialize()和unserialize()时使用这些方法,以确保您有一个钩子来删除一些属性,如数据库连接,并在加载时将它们设置回来.在会话中存储对象时会发生这种情况.
从 PHP 7.4 开始,将有新方法 __serialize() 和 __unserialize() 可用,它们应该稍微改变 __sleep 和 __wakeup 魔术方法的用法。
PHP 目前提供了两种自定义对象序列化机制:__sleep()/__wakeup() 魔术方法,以及 Serializable 接口。不幸的是,这两种方法都有将在下面讨论的问题。该 RFC 建议添加一个新的自定义序列化机制来避免这些问题。
更多 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;
Run Code Online (Sandbox Code Playgroud)
用法与 Serializable 接口非常相似。从实际角度来看,主要区别在于,不是在 Serializable::serialize() 中调用 serialize(),而是直接返回应该序列化为数组的数据。
下面的例子说明了 __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"];
}
}
Run Code Online (Sandbox Code Playgroud)
这通过将实际的序列化和反序列化留给序列化器的实现来解决 Serializable 的问题。这意味着我们不必再共享序列化状态,从而避免与反向引用排序相关的问题。它还允许我们将 __unserialize() 调用延迟到反序列化结束。
| 归档时间: |
|
| 查看次数: |
22941 次 |
| 最近记录: |