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

时间:2017-09-27 07:32:21

标签: php magic-methods

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

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);

真正的目的是什么?是用于调试还是其他什么?

2 个答案:

答案 0 :(得分:5)

__set_state可以与var_export

相关联地理解

如果您阅读the docs

  

var_export()获取有关给定变量的结构化信息。它   类似于var_dump(),但有一个例外:返回   表示是有效的PHP代码。

比较两者:

  1. 的var_dump($ A)

    对象(A)#1(2){[“var1”] => int(5)[“var2”] => string(3)“foo”}

  2. var_export($ A)

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

  3. (奖金)序列化($ a)

    0: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的惯例 - 那里没有魔法。但这只是我的拙见。

答案 1 :(得分:2)

调用

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

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

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_ ==&gt; 100

     

value2_ ==&gt; 100

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

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

您可以在__set_state方法中添加任何内容。