• PHP的序列化、对象、反射、异常与错误


    1. 怎么理解php里面的序列化与反序列化?

    序列化是将对象转换为字节流。反序列化就是将流转换为对象。
    这两个过程结合起来,可以轻松地存储和传输数据,在网络中可以做到跨平台、快速传输。

    两种序列化方式serialize和json

    1)serialize和json序列化结果的区别

    分别用serialize/unserialize函数与json_encode/json_decode函数对对象数组进行序列化和反序列化:

    // 对象  
    $web = new stdClass;  
    $web->site = 'tantengvip';  
    $web->owner = 'tuntun';  
    $web->age = 5; 
    var_dump(serialize($web));
    var_dump(unserialize(serialize($web)));
    var_dump(json_encode($web));
    var_dump(json_decode(json_encode($web)));
    // 结果
    string(87) "O:8:"stdClass":3:{s:4:"site";s:10:"tantengvip";s:5:"owner";s:6:"tuntun";s:3:"age";i:5;}"
    object(stdClass)#2 (3) {
      ["site"]=>string(10) "tantengvip"
      ["owner"]=>string(6) "tuntun"
      ["age"]=>int(5)
    }
    string(46) "{"site":"tantengvip","owner":"tuntun","age":5}"
    object(stdClass)#2 (3) {
      ["site"]=>string(10) "tantengvip"
      ["owner"]=>string(6) "tuntun"
      ["age"]=>int(5)
    }
    
    // 数组:  
    $web = array();  
    $web['site'] = 'tantengvip';  
    $web['owner'] = 'tuntun';  
    $web['age'] = 5;  
    var_dump(serialize($web));
    var_dump(unserialize(serialize($web)));
    var_dump(json_encode($web)); 
    var_dump(json_decode(json_encode($web), true));
    // 结果
    string(74) "a:3:{s:4:"site";s:10:"tantengvip";s:5:"owner";s:6:"tuntun";s:3:"age";i:5;}"
    array(3) {
      ["site"]=>string(10) "tantengvip"
      ["owner"]=>string(6) "tuntun"
      ["age"]=>int(5)
    }
    string(46) "{"site":"tantengvip","owner":"tuntun","age":5}"
    array(3) {
      ["site"]=>string(10) "tantengvip"
      ["owner"]=>string(6) "tuntun"
      ["age"]=>int(5)
    }
    

    不管是对象还是数组,用serialize和json进行序列化,反序列化回来的结果都相同,区别在于序列化的格式。

    2)serialize和json序列化的对比

    序列化 serialize json
    可读性 编码后的文本不可读,无法被其他语言的系统引用。 变量序列化后可读性强,可以给其他系统使用。
    编码格式 允许非UTF-8的变量。 只对UFT-8的数据有效。
    处理对象 支持除了stdClass外的其他实例。 只对stdClass类的示例有效。
    速度 较小数据的情况下,serialize比json快数量级。 大量数据的情况下,json比serialize稍差。
    使用范围 对象的存储使用serialize。 与对象无关的数据存储可以使用json,如包含大量数字的数组等。

    3)serialize和json序列化对对象内成员变量和方法的处理

    class Test {
        private $pri = 'pri';
        public $class = 'Test';
        public function __construct() {
            $this->class = 'Test construct';
            $this->pri = 'pri construct';
      }
      public function hello() {
            echo 'hello!';
      }
    }
    $test = new Test();
    var_dump(serialize($test));
    var_dump(unserialize(serialize($test)));
    var_dump(json_encode($test));
    var_dump(json_decode(json_encode($test)));
    // 结果
    string(86) "O:4:"Test":2:{s:9:"?Test?pri";s:13:"pri construct";s:5:"class";s:14:"Test construct";}"
    object(Test)#2 (2) {
      ["pri":"Test":private]=>string(13) "pri construct"
      ["class"]=>string(14) "Test construct"
    }
    string(26) "{"class":"Test construct"}"
    object(stdClass)#2 (1) {
      ["class"]=>string(14) "Test construct"
    }
    

    serialize序列化和反序列化只要是类的变量都可以,但是类的成员方法都无法进行序列化和反序列化。
    而json序列化和反序列化只能序列化/反序列化类中的公有成员变量,不能序列化/反序列化类中的私有成员变量,其成员方法也无法进行序列化和反序列化。

    2. 怎么遍历一个对象,有哪几种方式?

    1)使用foreach遍历对象

    如果在对象之外用foreach只能输出公有的属性,不能输出私有的和保护的属性。

    class object {
        public $a = 1;
        protected $b = 2;
        private $c = 3;
    }
    $obj = new object();
    foreach($obj as $key => $val){
        echo $key.'-'.$val;
    }
    // 结果
    a-1 
    

    2)迭代器

    • 实现Iterator(迭代器)接口,让对象自行决定如何遍历以及每次遍历时哪些值可用。

    一般的迭代器内部需要下面的方法:

    Iterator extends Traversable {
        // 返回当前元素
        abstract public mixed current (void) 
        // 返回当前元素的索引
        abstract public scalar key (void)
        // 移动到下一个元素
        abstract public void next (void)  
        // 从头重新开始
        abstract public void rewind (void)  
        // 检查迭代结尾
        abstract public boolean valid (void)  
    }
    

    Example:实现Iterator接口的对象遍历

    class MyIterator implements Iterator {
        private $var = array();
    
        public function __construct($array) {
            if (is_array($array)) {
               $this->var = $array;
            }
        }
    
        public function rewind() {
            echo "倒回第一个元素
    ";
            reset($this->var);
        }
    
        public function current() {
            $var = current($this->var);
            echo "当前元素: $var
    ";
            return $var;
        }
    
        public function key() {
            $var = key($this->var);
            echo "当前元素的键: $var
    ";
            return $var;
        }
    
        public function next() {
            $var = next($this->var);
            echo "移向下一个元素: $var
    ";
            return $var;
        }
    
        public function valid() {
            $var = $this->current() !== false;
            echo "检查有效性: {$var}
    ";
            return $var;
        }
    }
    
    $values = array(1,2,3);
    $it = new MyIterator($values);
    
    foreach ($it as $k => $v) {
         print "此时键值对 -- key $k: value $v
    
    ";
    }
    // 结果为:
    倒回第一个元素
    当前元素: 1
    检查有效性: 1
    当前元素: 1
    当前元素的键: 0
    此时键值对 -- key 0: value 1
    
    移向下一个元素: 2
    当前元素: 2
    检查有效性: 1
    当前元素: 2
    当前元素的键: 1
    此时键值对 -- key 1: value 2
    
    移向下一个元素: 3
    当前元素: 3
    检查有效性: 1
    当前元素: 3
    当前元素的键: 2
    此时键值对 -- key 2: value 3
    
    移向下一个元素: 
    当前元素: 
    检查有效性: 
    
    • 不实现接口Iterator,实现他的子接口IteratorAggregate。

    使用Iterator的执行过程如下:
    1、将对象中数组的元素置为第一个。
    2、输出当前元素的值。
    3、检查有效性。
    4、输出当前元素的值。
    5、输出当前元素的键。
    6、移向下一个元素,重复2、3、4、5步骤。
    7、如果某索引下没有值,就此中断。

    缺点是需要实现5个函数,可以用IteratorAggregate接口替代Iterator,因为IteratorAggregate只需要实现一个方法IteratorAggregate::getIterator()就能完成对象的遍历。

    Example:通过实现IteratorAggregate来遍历对象

    class myData implements IteratorAggregate {
        public $property1 = "Public property one";
        public $property2 = "Public property two";
        public $property3 = "Public property three";
    
        public function __construct() {
            $this->property4 = "last property";
        }
    
        public function getIterator() {
            // ArrayIteratoer从PHP数组创建一个迭代器,当其和IteratorAggregate类一起使用时,免去了直接实现Iterator接口的方法的工作。
            return new ArrayIterator($this); 
        }
    }
    
    $obj = new myData;
    foreach($obj as $key => $value) {
        var_dump($key, $value);
        echo "
    ";
    }
    // 结果为:
    string(9) "property1"
    string(19) "Public property one"
    
    string(9) "property2"
    string(19) "Public property two"
    
    string(9) "property3"
    string(21) "Public property three"
    
    string(9) "property4"
    string(13) "last property"
    

    3. 反射是什么意思,一般应用在什么场景?

    反射指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类、方法、属性、参数等的详细信息,包括注释。简而言之,就是通过对象实例反向分析,从而获取其信息。

    用途:

    1)获取类的信息,生成描述文档
    2)对对象进行调试

    使用场景:

    MVC里,依赖注入、控制反转,用的就是反射的特性

    4. 讲讲你对php的异常和错误的理解。

    异常是指程序运行中不符合预期情况以及与正常流程不同的状况。错误则属于自身问题,是一种非法语法或者环境问题导致的、让编译器无法通过检查设置无法运行的情况。

    PHP一旦遇到非正常代码,通常都是触发错误,而不是抛出异常。换言之,PHP无法自动捕获有意义的异常,只有主动throw后,才能捕获异常。

    捕获这个异常需要使用if……else结构,保证代码是正常的,然后作出逻辑判断,遇到错误,就手动抛出异常,再捕获,即try……catch。

  • 相关阅读:
    牛客 公式字符串求值
    牛客 括号字符串的有效性和最长有效长度
    POJ-2533 Longest Ordered Subsequence ( DP )
    HDU-1160 FatMouse's Speed ( DP )
    HDU-1260 Tickets ( DP )
    HDU-1074 Doing Homework( 状压DP )
    HDU-1069 Monkey and Banana ( DP )
    HDU-1087 Super Jumping! Jumping! Jumping!( DP )
    HDU-3746 Cyclic Nacklace ( kmp )
    HDU-2087 剪花布条 ( kmp )
  • 原文地址:https://www.cnblogs.com/sunshineliulu/p/7357926.html
Copyright © 2020-2023  润新知