zoukankan      html  css  js  c++  java
  • PHP序列化与反序列化学习

    序列化与反序列化学习

    把对象转换为字节序列的过程称为对象的序列化;把字节序列恢复为对象的过程称为对象的反序列化。

    <?php
    
    class UserInfo  {
    
        public $name = "admin";
    
        public $age = 1;
    
        public $blog = "file:///var/www/html/flag.php";
    
    }
    
    $data = new UserInfo();
    
    echo serialize($data);
    
    ?>
    

    页面显示:
    O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:1;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
    此处调用到了serialize函数,对数据进行了序列化并返回了一组字符串。

    <?php
    $sites = array('t1', 'tt2', 'ttt3');
    $serialized_data = serialize($sites);
    echo  $serialized_data;
    ?>
    

    输出:a:3:{i:0;s:2:"t1";i:1;s:3:"tt2";i:2;s:4:"ttt3";} 对这个序列化的输出进行分析:

    a:3表示数组里面有三个分类。
    i:0:表示第一个数组。  
    s:2:表示有两个字符
    "t1":表示内容为't1'。
    
    i:1:表示第二个数组。
    s:3:"tt2":标识有三个字符,内容为'tt2'
    

    反序列化: <?php $sites = array('t1', 'tt2', 'ttt3'); $serializeddata = serialize($sites); #echo $serializeddata; $unserializeddata = unserialize($serializeddata); printr($unserializeddata); ?>

    此时又生成回:Array ( [0] => t1 [1] => tt2 [2] => ttt3 )

    其中:o表示对象,a表示数组,s表示字符,i表示数字

    在php中,一个类可以包含有属于自己的常量,变量(属性)以及函数(方法)
    一段反序列化,序列化代码:(来自https://www.jianshu.com/p/8f498198fc3d)

    <?php
    class Test  
    {  
        public $handle1;  
        private $handle2;
        protected $handle3;
    
        public function __construct($handle1,$handle2,$handle3)  
        {  
            $this->handle1 = $handle1;
            $this->handle2 = $handle2;
            $this->handle3 = $handle3;
            echo '__construct<br />';  
        }  
        public function __destruct()  
        {  
            echo $this->handle2.'<br />';
            echo '__destruct<br />';
        }  
        public function __wakeup()  
        {  
            echo '__wakeup<br />';
        }
    }
    
    $obj = new Test("111","222","333");
    $see = serialize($obj);
    print 'Serialized: ' . $see . '<br />';
    # %00Test%00v2 表示 private      %00*%00v3 表示protected
    $ss = 'O:4:"Test":3:{s:7:"handle1";s:3:"777";s:17:"%00Test%00handle2";s:3:"888";S:14:"%00*%00handle3";s:3:"999";}';
    $obj2 = unserialize($ss);
    var_dump($obj2);
    
    ?>  
    

    在这段php代码中:
    $obj = new Test("111","222","333");创建了类的实例,所以使用到了new的关键字。

    在类中对于静态方法和静态属性的引用:

    class Test{
    public static $test = 1;
    public static function test(){
      }
    }
    

    此时我们不用实例化对象,直接使用Test::$test就能获取$test属性的值,Test::test()这样可以直接调用静态方法test。

    范围解析操作符:可以用于访问静态成员,类常量,还可以用于覆盖类中的属性和方法,即::

    <?php
    class MyClass {
        const CONST_VALUE = 'A constant value';
    }
    
    $classname = 'MyClass';
    echo $classname::CONST_VALUE; // 自 PHP 5.3.0 起
    echo '<br>';
    echo MyClass::CONST_VALUE;
    ?>
    

    此时我们就使用了变量静态地调用了类MyClass当中的常量,注意自 PHP 5.3.0 起,可以通过变量来引用类,但该变量的值不能是关键字。
    结果:

    A constant value
    A constant value
    

    使用子类覆盖父类:

    <?php
    class OtherClass extends MyClass
    {
        public static $my_static = 'static var';
    
        public static function doubleColon() {
            echo parent::CONST_VALUE . "
    ";
            echo self::$my_static . "
    ";
        }
    }
    
    $classname = 'OtherClass';
    echo $classname::doubleColon(); // 自 PHP 5.3.0 起
    
    OtherClass::doubleColon();
    ?>
    

    此时PHP不会调用父类中已被覆盖的方法,是否调用父类的方法取决于子类。

    调用父类方法:

    <?php
    class MyClass
    {
        protected function myFunc() {
            echo "MyClass::myFunc()
    ";
        }
    }
    
    class OtherClass extends MyClass
    {
        // 覆盖了父类的定义
        public function myFunc()
        {
            // 但还是可以调用父类中被覆盖的方法
            parent::myFunc();
            echo "OtherClass::myFunc()
    ";
        }
    }
    
    $class = new OtherClass();
    $class->myFunc();
    ?>
    

    输出:
    MyClass::myFunc() OtherClass::myFunc()
    其中-> 是对象成员访问符号。
    例如:$this->name = $value
    其中:$this是特定变量,它代表了他的类,通过->我们可以访问其类的成员,所以这段代码的意思就是:将当前类的name变量的值设置为 $value.

    继承:类可以在声明中用 extends 关键字继承另一个类的方法和属性。PHP不支持多重继承,一个类只能继承一个基类。

    class Father
    {
        public $aar;
    
        public function bar ()
        {
            return 'father';
        }
    
        final public function testFinal ()
        {
            return 'father';
        }
    
    }
    class Son extends father
    {
        public function bar ()
        {
            return 'son';
        }
    
        public function callFatherBar ()
        {
            return parent::bar();
        }
        //Cannot override final method Father::testFinal()
        // public function testFinal()
        // {
    
        // }
        //如果父类定义是设置了final 则父类方法均不能覆盖 final class Father
        //属性无final的概念
    }
    echo (new Son())->bar();//son
    echo (new Son())->callFatherBar();//father  
    

    前面写类方法获取属性我们使用的是::这是在静态环境中,对于非静态的,我们使用$this->property即可。
    属性的声明由关键词:public,protected或者private开头,后面加上变量。
    即:

    public $handle1;  
    private $handle2;
    protected $handle3;
    

    我们声明了三个不同属性的变量:

    三个关键字控制 public 公有;protected 受保护;private 私有的

    public:可以在任何地方被访问
    
    protected:可以被自身或其子类和父类访问,表示方式是在变量名前加个%00*%00
    
    private:只能被其定义所在的类访问,表示方式是在变量名前加上%00类名%00
    

    还有关于常量的定义:
    const constant = 'constant value';

    构造函数

    在PHP5中,可以在一个类中定义一个构造函数,具有构造函数的类,当每次创建新的对象的时候会先调用这个方法,以方便我们在使用对象前做一些初始化工作。

    class Father
    {
         function __construct ()//不可为private
        {
            echo 'Father';
        }
    }
    
    class Child extends Father
    {    //当Child无构造函数时,自动调用父类的 Father
        function __construct ()
        {
            echo 'Child';
        }
    
        function callFatherConstruct ()
        {
            parent::__construct();
        }
    }
    
    $obj = new Child;//Child
    
    $obj->callFatherConstruct();//Father
    

    子类中定义了构造函数,不会隐式的调用父类的构造函数,需要用parent::__construct()调用,如果子类没有构造函数,父类的构造函数将和普通函数一样被子类继承。

    参考链接:https://www.cnblogs.com/ValleyUp/p/11181141.html

    magic函数

    php类包含magic函数的特殊函数,magic函数命名是以符号 __ 开头的,例如 __ sleep, __ wakeup,__ construct, __ destruct等。
    这些函数经常会被自动调用,construct当一个对象创建时被调用,destruct当一个对象销毁时被调用。
    常用的魔术方法有:

    serialize():检查类中是否存在一个魔术方法 __sleep(),优先调用此方法,然后执行序列化操作。
    unserialize():检查是否存在一个 __wakeup() 方法,优先调用此方法
    __construct():当一个对象创建时被调用
    __destruct():当一个对象销毁时被调用
    __call():当调用一个未定义(包括没有权限访问)的方法是调用此方法
    __callStatic():处理静态方法调用
    __get():当调用一个未定义的属性时访问此方法
    __set(): 给一个未定义的属性赋值时调用
    __isset():当在一个未定义的属性上调用isset()函数时调用此方法
    __unset():当在一个未定义的属性上调用unset()函数时调用此方法
    __sleep():常用于提交未提交的数据,或类似的清理操作,在对象被序列化之前运行
    __wakeup():用于预先准备对象需要的资源,在对象被反序列化之后被调用
    __toString():用于一个类被当成字符串时应怎样回应。例如 echo $obj; 应该显示些什么。此方法必须返回一个字符串
    __invoke():当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
    __set_state(),:当调用var_export()时,这个静态 方法会被调用(自PHP 5.1.0起有效)。本方法的唯一参数是一个数组,其中包含按array(’property’ => value, …)格式排列的类属性。
    __clone() :对象赋值时使用的引用赋值,使用clone方法复制一个对象时,对象会自动调用__clone魔术方法
    

    当序列化字符串中,表示对象属性个数的值大于实际属性个数时,那么就会跳过wakeup方法的执行。
    拿php一个代码为例,综合上面学习的进行理解:

    <?php
    class Connection   //定义一个类,类名为Connection
    {
        protected $link;    //定义一个变量属性,可以被自身或其子类和父类访问
        private $server, $username, $password, $db;   //定义了四个变量属性,只能被其定义所在的类访问。
    
        public function __construct($server, $username, $password, $db)    //定义一个方法,可以在任何地方被访问
        {
            $this->server = $server;             //$this是特定变量,它代表了他的类connection,通过->我们可以访问其类的成员如server等,将当前类的server变量的值设置为 $server.
            $this->username = $username;         //同上,以下皆是。
            $this->password = $password;
            $this->db = $db;
            $this->connect();
        }
    
        private function connect()  //定义一个方法,只能被其定义所在的类访问
        {
            $this->link = mysql_connect($this->server, $this->username, $this->password);    //当前的link,用来连接mysql数据库。
            mysql_select_db($this->db, $this->link);
        }
    
        public function __sleep()     //提交数据时,要进行的行为。
        {
            return array('server', 'username', 'password', 'db');     //提交的时候返回
        }
    
        public function __wakeup()     //重新建立数据库连接
        {
            $this->connect();
        }
    }
    ?>
    

    序列化得到字符串格式:

    s:size:value:表示字符。  
    a:size:{键值;值;元素},
    例如a:3:{i:0;s:2:"t1";i:1;s:3:"tt2";i:2;s:4:"ttt3";}  
    i:0,表示第一个数组,s:2表示有两个字符,"t1",表示字符为t1。
    O:对象长度:对象类名称:成员变量数:{类型:字符个数长度:"具体值";类型:长度:"具体值";.......}  
    O:4:"Test":3:{s:7:"handle1";s:3:"111";s:13:"Testhandle2";s:3:"222";s:10:"*handle3";s:3:"333";}
    O:1:"A":2:{s:6:" A var";i:1139586461;s:4:"var2";s:1:"b";}
    

    反序列化能将类的成员变量还原,但是不能将类的方式还原。
    解析顺序:

    jsonencode/jsondecode
    <?php
    $a=array('a'=>'cuit','b'=>'syclover','c'=>'dog');
    //序列化数组
    $s=json_encode($a);
    echo $s;
    //反序列化
    $o=json_decode($s);
    ?>
    

    输出:{"a":"cuit","b":"syclover","c":"dog"}

    e></p>

  • 相关阅读:
    手把手教你学Git
    服务器上Mysql的安装与配置
    python 5
    python 4
    python 3
    python 2
    区分命令行模式和Python交互模式
    CUDA编程模型之内存管理
    多目标优化算法-NSGA2
    C# ListView 如何添加列标头
  • 原文地址:https://www.cnblogs.com/ophxc/p/12895995.html
Copyright © 2011-2022 走看看