PHP中魔术方法__set_state的真正目的是什么?

What is the real purpose of magic method __set_state in PHP?

我正在学习魔术方法,阅读每个站点,举每个例子,但对我来说没有任何意义。像这样的例子:

class A
{
    public $var1;
    public $var2;

    public static function __set_state($an_array) // As of PHP 5.1.0
    {
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
                                            //    'var1' => 5,
                                            //    'var2' => 'foo',
                                            // ));
var_dump($b);

真正的目的是什么?是为了调试什么的?

__set_state 被调用以响应传递给 var_export 函数的对象实例。

var_export 输出或 returns 变量的可解析字符串表示形式。

var_export 有一个可选的第二个参数——一个布尔值,用于确定作为第一个参数传递的变量是否作为字符串而不是输出返回。

一个例子:

class Dummy {
  private $value1_;
  private $value2_;

  function __construct() {
    $this->value1_ = 100;
    $this->value2_ = "100";
  }

  static function __set_state(array $array) {
    foreach($array as $k => $v) {
      echo("$k ==> $v <br/>");
    }
  }
}
$aDummy = new Dummy();
//var_export by it self will output Dummy::__set_state(array( 'value1_' => 100, 'value2_' => '100', ))
var_export($aDummy);
eval(var_export($aDummy, true) . ';');

现在输出是这样的:

value1_ ==> 100

value2_ ==> 100

var_export 可以为定义了 __set_state 方法的 Dummy 类型生成可执行的 PHP 代码。

var_export 接受一个参数,它必须是一个数组。它将包含调用它的实例的属性或字段的键值对。

您可以在 __set_state 方法中放入任何您想要的东西。

__set_state可以和var_export

联系起来理解

如果你阅读 the docs:

var_export() gets structured information about the given variable. It is similar to var_dump() with one exception: the returned representation is valid PHP code.

比较两者:

  1. var_dump($a)

    object(A)#1 (2) { ["var1"]=> int(5) ["var2"]=> string(3) "foo" }

  2. var_export($a)

    A::__set_state(array( 'var1' => 5, 'var2' => 'foo', ))

  3. (奖金)serialize($a)

    O:1:"A":2:{s:4:"var1";i:5;s:4:"var2";s:3:"foo";}

因此第二个是有效的 PHP 代码,您可以 运行 它并以类似的对象结束。

那么,如果删除 __set_state 方法会发生什么?让我们试试:

class A
{
    public $var1;
    public $var2;  
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

var_export($a); 
// A::__set_state(array( 'var1' => 5, 'var2' => 'foo', ))

仍然有效,对吧?那就叫它吧

class A
{
    public $var1;
    public $var2;  
}

$a = A::__set_state(array( 'var1' => 5, 'var2' => 'foo', )) 
// Exception: Call to undefined method A::__set_state()

我们带回去看看:

class A
{
    public $var1;
    public $var2;

    public static function __set_state($an_array) // As of PHP 5.1.0
    {
        $obj = new A;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }    
}

$a = A::__set_state(array( 'var1' => 5, 'var2' => 'foo', ));
var_dump($a); 
// object(A)#1 (2) { ["var1"]=> int(5) ["var2"]=> string(3) "foo" } 

所以 __set_state 方法的真正目的是初始化一个对象,以防有人用 var_export.

“序列化”它

为什么有人会需要它?用 serialize 序列化的对象需要用 unserialize 反序列化。但是 var_export 保存在文件中的对象可能只是被包含在内,因为它只是一个有效的 PHP 代码。

编辑:

我不会真的调用此方法 magic(即使它在文档中这样描述)因为它没有什么神奇之处。 PHP 只是假设它在 var_export 被调用时就在那里,如果你想使用 var_export 产生的任何东西,它就必须在那里。我会说这只是一个约定,它被称为 __set_state - 那里没有魔法。但这只是我的拙见。