php反序列化基础

一.面向对象

(1)简介

在面向对象的程序设计(OOP)中,对象是一个由信息及对信息进行处理的描述所组成的整体,是对现实世界的抽象。 在现实世界里我们所面对的事情都是对象,如计算机、电视机、自行车等。面向对象思想的核心:计算机模拟现实世界,解决现实世界的问题。 对象的主要三个特性: 对象的行为、对象的形态、 对象的表示。

对象的行为:可以对对象施加那些操作,开灯,关灯就是行为。
对象的形态:当施加那些方法是对象如何响应,颜色,尺寸,外型。
对象的表示:对象的表示就相当于身份证,具体区分在相同的行为与状态下有什么不同。

(2)内容

【1】类的基本定义-关键词(class)
     每个类的定义都是以关键词Class开头,后面类名,后面跟着一对花括号,里面包含有类的属性与方法的定义。类名实际上和变量名、函数名这些命名规则很相似,都需要遵守PHP中自定义名称的规则,一般类的声明从类的属性和类的方法来考虑,不过也可以什么也没有。

     类属性,就相当于类的变量,就是成员属性,比如,人类的属性就有姓名,年龄等属性,所以这个属性一般描述这个类的基本特征;属性声明是由关键字 public,protected或者 private开头,设定其属性的访问控制可见性,然后跟一个普通的变量声明来组成。PHP5为了向后兼容仍然可以用var声明属性,被认为是public修饰。PHP属性中的变量可以初始化,但是初始化的值必须是常数,这里的常数是指 PHP 脚本在编译阶段时就可以得到其值,而不依赖于运行时的信息才能求值。

       类的方法,就相当于这个类的函数,也就是成员方法,例如,人类可以学习,说话等行为。不要定义一些和类无关的,虽然程序不会报错,但是不符合面向对象思想。方法的声明也是由关键字 public,protected或者 private开头,设定其方法的访问控制可见性,后面跟一个函数。


【2】类实例化对象-关键词(new)
       面向对象程序基本单位就是对象,对象是用类实例化产生的,所以,先有类定义才有对象。利用关键词new后面跟上类名。如果定义的类属于一个命名空间,就要使用完整的名称。 一个类可以实例化多个对象,并且对象之间是互相独立的。

【3】访问成员属性以及方法 -访问符(->) 
     一般可以通过对象的引用名后面加上一个特殊的运算符号"->"来完成对象成员的访问。

【4】特殊对象的引用-关键词(this)
    我们可以用到$this,可以在对象内部来访问,相当于代表自己。

【5】构造方法(__construct())
   声明构造方法和普通声明方法类似。用__construct()进行声明。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。那么我们就可以在对象实例化前对属性进行赋值操作,注意如果需要传入参数,那么实例化类的时候,后面要加小括号传入参数。  另外为了向后兼容方法名与类名一样也是表示构造方法,但是我们不常用这种同名的,因为万一类名改变了,构造方法的类名也要统一修改。 


【6】析构方法(__destruct())
       与构造方法对应的就是析构方法,PHP 5 引入析构方法的概念,声明的话用__destruct()。

       通常对象的引用会在页面运行结束时候失去。在PHP中有一种回收的机制,当对象不能被访问时候,就会自动启动回收的程序,收回对象在堆中占用的内存空间。而析构方法则是在回收对象前进行调用的。可以利用它做一些文件关闭,或者释放结果集等。

【7】封装性-关键词(public,protected,private)
      面向对象三大特征之一,把对象的全部成员属性,和全部方法结合在一起,形成一个不可分割的独立单位对象。信息隐蔽,尽可能对属性进行封装,而只保留一个对外部的接口使之发生联系。

      对象中的成员属性如果没有被封装,一旦对象完成创建,就比如让别人知道你有多少钱,还可以随意花你的钱一样,对象的外部也可以随意调用其中的方法。

     封装的原则就是要求对象以外的部分不能随意获取对象的内部数据(成员属性以及方法),对属性和方法进行封装就需要使用关键词public,protected,private这些进行访问控制。


【8】继承性-关键词(extends)
     用关键词extends来继承父类,父类也叫做基类或者超类,子类也可以叫做派生类。PHP中只能单继承,不可以一个类继承多个父类。

     比如,当扩展一个类,子类就会继承父类所有公有的和受保护的方法。除非子类覆盖了父类的方法,被继承的方法都会保留其原有功能。继承对于功能的设计和抽象是非常有用的,而且对于类似的对象增加新功能就无须重新再写这些公用的功能。

【9】访问控制-关键词(public,protected,private)
      对属性或方法的访问控制,是通过在前面添加关键字 public(公有)protected(受保护)或 private(私有)来实现的。被定义为公有的类成员可以在任何地方被访问。被定义为受保护的类成员则可以被其自身以及其子类和父类访问。被定义为私有的类成员则只能被其定义所在的类访问。只有public方法可以在类的外部调用。

     类的属性前面必须加关键词,定义为公有,受保护,私有之一,如果用var定义默认视为公有。类的方法前面如果不加关键词,默认是公有。另外构造方法不要定义私有,这样会创建对象的时候报错。

公有的访问修饰符public,对访问类中的成员没有限制,而且外部成员也可以访问这个类中的成员,以及子类也可以访问属性或者方法。
 

受保护的访问修饰符protected,对于父类,外部不能获取其属性或者方法,只能在内部使用。对于该类的子类内部具有访问权限,但是外部不能进行访问。这样可以实现对对象的封装。
 

私有的访问修饰符private,这种的范围仅限于在父类的内部进行使用,父类外部以及子类都访问不到。

【10】类常量-关键词(const)
        可以把在类中始终保持不变的值定义为常量。在定义和使用常量的时候不需要使用 $ 符号。常量的值必须是一个定值,不能是变量,类属性,数学运算的结果或函数调用。其中类外如果访问的话使用::(范围解析操作符),通过"类名::常量"来获取。

【11】关键字static
      声明类属性或方法为静态,就可以不实例化类而直接访问。静态属性不能通过一个类已实例化的对象来访问(但静态方法可以)。由于静态方法不需要通过对象即可调用,所以伪变量 $this 在静态方法中不可用。静态属性不可以由对象通过 -> 操作符来访问。static用于定义静态成员属性或者方法,可以直接用类名方式进行调用,不用实例化对象。

     就像其它所有的 PHP 静态变量一样,静态属性只能被初始化为文字或常量,不能使用表达式。所以可以把静态属性初始化为整数或数组,但不能初始化为另一个变量或函数返回值,也不能指向一个对象。

     如果一个类中声明了一个静态属性,那么不管这个类被实例化多少次,或者没有实例化,这个static成员总是唯一存在,在多个对象中共存。因为这个static标识的成员属于类的,它不属于任何对象。
类内:由于类的静态属性不属于对象,所以不能使用$this访问,而是使用self关键词。
    self::静态成员属性名;
    self::静态成员方法名();
类外:
    类名::静态成员属性名;
    类名::静态成员方法();
    对象->静态成员方法();
    类中的静态方法中通过self访问静态成员,如果是父类的可以使用parent访问。因为非静态的成员必须通过对象调用,通常是$this。类外静态方法在对象不存在的时候可以直接通过类名进行调用,在对象存在的时候也可以用对象的引用进行调用。类定义的静态属性或者方法,在其子类中也能使用。

【12】关键字final
如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
【13】关键字this,self,parent,static的区别
     $this指向当前的对象,也就是当前实例化的类,在实例化的时候来确定指向。$this无法指向静态变量和静态方法。self指向类本身,不指向任何已经实例化的对象,主要用来调用静态方法和静态变量。parent指向父类,经常用于子类重写父类的方法,这里要记得子类方法如果重写了父类方法其访问权限不能低于父类被覆盖的方法权限。static用于定义静态成员属性或者方法,可以直接用类名方式进行调用,不用实例化对象。

【14】关键字instanceof
使用instanceof关键字可以判断一个对象是都是某个类的实例,类的子类,或者是某个特定的接口。实际上这个关键字算是php的类型运算符。
【15】抽象类-关键词(abstract)
     PHP 5 支持抽象类和抽象方法。一个类被定义为抽象的,那么它不可以被实例化,除非子类继承它并且实现它所有的抽象方法。定义抽象类相当于开发规范,这种规范子类必须去遵守实现,才可以进行实例化。声明抽象方法用关键字修饰符abstract。

     抽象类,一个类中如果有一个抽象方法,那么这个类就是抽象类,抽象类也要使用关键字修饰符abstract,当然抽象类中也可以有不抽象的成员属性或者方法,但是其访问权限不能用private关键词修饰。

【16】接口interface与实现接口implements
       使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。它是一种特殊的抽象类,接口也算是特殊的类。如果一个抽象类中所有的方法都是抽象方法,那么我们也可以用接口去进行声明,而且因为都是抽象方法,也就不用写abstract。而是是通过interface关键字来定义的接口类。

      接口中声明的方法必须都是抽象方法,并且不能在接口中声明变量,只能用const关键字来成名类常量但是不能被覆盖,另外接口中的所有成员方法都必须是public的访问权限。接口也可以继承使用extends。实现多个接口的时候方法不能重名。接口的实现是通过implements关键词。一个类只能继承一个类,但是可以实现多个接口,不过先写extends 后写 implements。

【17】多态性
       多态最直接的定义就是让具有继承关系的不同类对象,可以对相同名称的成员函数进行调用,产生不同的反应效果。在PHP中多特性体现在方法的重写。重写就是指一个子类中可以重新修改父类中的某些方法,使其具有自己的特征。重写要求子类的方法和父类的方法名称相同,这个可以通过声明抽象类或者接口来规范。另外如果相对父类的方法进行重写,但又想用父类的方法可以用parent关键词。

【18】Trait

        PHP5.4后,Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用 method。Trait 和 Class 组合的语义定义了一种减少复杂性的方式,避免传统多继承和 Mixin 类相关典型问题。

      声明类的时候我们用class,那么声明trait当然就用关键词trait。但是他无法自身实例化,必须混入到类中,利用use去使用。另外类有的特性trait都有,也支持final,static,abstract等这些修饰符。从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。通过逗号分隔,在 use 声明列出多个 trait,可以都插入到一个类中。如果两个 trait 都插入了一个同名的方法,如果没有明确解决冲突将会产生一个致命错误。为了解决多个 trait 在同一个类中的命名冲突,需要使用 insteadof操作符来明确指定使用冲突方法中的哪一个。

二.反序列化

(1)简介

序列化:将变量转换为可保存或传输的字符串的过程;
反序列化:在适当的时候把这个字符串再转化成原来的变量使用。
优点:这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。
通过序列化与反序列化我们可以很方便的在PHP中进行对象的传递。本质上反序列化是没有危害的。但是如果用户对数据可控那就可以利用反序列化构造payload攻击。

(2)字符解释

字符详解

详细地址PHP反序列化入门手把手详解-CSDN博客

O:6:"Person":3:{s:4:"name";s:3:"tom";  s:11:"Personage";  i:18;   s:6:"*sex"; s:3:"boy";}

O : 自定义对象 object
6  : 类名的长度
:3 : 3个成员属性
S:4 : 你的成员属性名  长度为4 ,并且是一个字符串   string
S:3 : 刚刚那个成员属性对应的值 是string类型,并且长度是3位
s:11:"Personage" : 因为该属性是私有属性,所以需要在属性名前加上类名,方便我们进行反序列化的时候的识别.
i:18 :  18是age的属性值 , i是代表  integer类型

s:6:"*sex";  sex这个属性是一个受保护的属性,特征就是 * 号

s:3:"boy : 代表 string类型,属性值长度为3位  boy对应是  sex的属性值

private和 protected详解

PHP 序列化的时候 private和 protected 变量会引入不可见字符%00,%00类名%00属性名 为private,%00*%00属性名 为protected,注意这两个 %00就是 ascii 码为0 的字符。这个字符显示和输出可能看不到,甚至导致截断,但是url编码后就可以看得清楚.我们可以将序列化的字符用urlencode编码之后,打印出来查看.

PHP常见

__construct:构造函数,会在每次创建新对象时先调用此方法
__destruct:析构函数,会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行

__toString:返回一个类被当做字符串时要输出的内容,此方法必须返回字符串并且不能在此方法中抛出异常,否则会产生致命错误。


__invoke:PHP5.3起,当尝试以函数的方式调用对象时,会调用此方法。
__call : 在对象中调用一个不可访问方法时调用。
__sleep:返回一个包含对象中所有应被序列化的变量名称的数组。serialize函数在序列化类时首先会检查类中是否存在__sleep方法。如果存在,会先调用此方法然后再执行序列化操作。并且只对__sleep返回的数组中的属性进行序列化。如果__sleep不返回任何内容,则null会被序列化,并产生E_NOTICE级别的错误。__sleep不能返回父类的私有成员,否则会产生E_NOTICE级别的错误。对于一些很大但不需要保存全部数据的对象此方法很有用。
即序列化serialize时会调用__sleep.


__wakeup:与__sleep相反,是在unserialize函数反序列化时首先会检查类中是否存在__wakeup方法,如果存在会先调用次方法然后再执行反序列化操作。用于在反序列化之前准备一些对象需要的资源,或其他初始化操作。
即反序列化unserialize时会自动调用__wakeup

  • 34
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值