php - 检测 __sleep 中的关闭以防止其序列化

标签 php serialization closures

当我尝试序列化一个包含闭包成员的对象时,会抛出异常。 为了避免包括闭包在内的成员序列化,我尝试了以下方法:

function __sleep(){
    $ref = new ReflectionClass($this);
    $props = $ref->getProperties();

    foreach ($props as $prop){
        $name = $prop->name;
        if (is_callable($this->$name)===false){
            $dream[] = $prop->name;
        }
    }
    return $dream;
}

不幸的是,这不起作用。有没有更好的方法来检测属性是否为闭包。

编辑:我通过让闭包知道是否序列化来解决我的问题

为此,我正在包装闭包本身。这是一个例子:

/**
 * Wrapper-class to prevent closure to be serialized.
 */
class WrappedClosure {

    private $closure = NULL;
    protected $reflection = NULL;

    public function __construct($function){
        if ( ! $function instanceOf Closure)
            throw new InvalidArgumentException();
        $this->closure = $function;
        $this->reflection = new ReflectionFunction($function);
    }

    /**
     * When the instance is invoked, redirect invocation to closure.
     */
    public function __invoke(){
        $args = func_get_args();
        return $this->reflection->invokeArgs($args);
    }

    // do nothing on serialization
    public function __sleep(){}

    // do nothing on serialization
    public function __wakeup(){}
}

// Assigning a wrapped closure to a member
$myObject->memberHoldingAClosure = 
    // Wrapping the closure 
    new WrappedClosure(
        function (){
            echo "I'am the inner closure.";
        }
    )
);

// the serialization doesn't throw an exception anymore
serialize($myObject);

最佳答案

对我来说很好:

class foo {
    protected $param = 'value';
    protected $closure = null;
    public function __construct() {
        $this->closure = function(){
            return 123;
        };
    }
    public function __sleep() {
        $serializable = array();
        foreach ( $this as $paramName => $paramValue ) {
            if ( !is_string($paramValue) && !is_array($paramValue) && is_callable($paramValue) ) {
                continue;
            }
            $serializable[] = $paramName;
        }
        return $serializable;
    }
}
$foo = new foo();
echo serialize($foo);

关于检查值是否是 Closure 类的实例(来自手册):

Anonymous functions are currently implemented using the Closure class. This is an implementation detail and should not be relied upon.

因此,我会将 is_closure($value) 函数实现为 return !is_string($value) && !is_array($value) && is_callable($value) 而不是return $value instanceof Closure 并希望有一天 PHP 开发人员会添加原生的 is_closure() 函数。

关于php - 检测 __sleep 中的关闭以防止其序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5580142/

相关文章:

python - 在 Ruby 中可以像这样使用 Lambdas 吗?

php - MYSQL 计算某个值作为值存在于表的字段中的次数

php - 在 MySQL 中设置 AUTO_INCREMENT 字段的起始值

java - 无法使用 Jackson 将对象序列化为 Json

c# - 如何在 CLR Procedure 中使用 Json Parser?

objective-c - 异步闭包在 Swift 中是如何工作的

Python 闭包没有按预期工作

php - MySQL 从特定列进行 SELECT 查询

php - 为什么 xdebug 没有出现在 phpinfo() 中

java - 在文件中写入多个对象并读取它们