PHP之魔术方法

一、前言

魔术方法是一种特殊的方法,像函数但又不是,当对对象执行某些操作时会覆盖 PHP 的默认操作。以'__'+字符串的一些默认方法,这些方法对后面会讲的序列化与反序列化漏洞起到了非常大的作用

常见的魔术方法有:__construct()、__destruct()、__get()、toString()、__sleep()、wakeup()、__invoke() 等等

二、常见的魔术方法

0x01 __construct() & __destruct()

            PHP之魔术方法_第1张图片

__construct()名为构造函数,会在创建对象时调用一次

PHP之魔术方法_第2张图片

既然有创建时调用的函数,那么也存在销毁时调用的函数,php将其称为析构函数

PHP之魔术方法_第3张图片

__destruct()如官方解释一般,在销毁时调用,但是什么时候会销毁,到很多文章都写用unset()

直接回收已创建的对象,但事实是:

PHP之魔术方法_第4张图片

 说明当一个程序结束后php会自动销毁最后调用一次__destruct()。ok,也就是说如果创建了一个对象那就一定会有销毁,只要程序运行从开始到结束一定会调用一次以上__destruct(),当然如果想要提前触发__destruct()方法可以用unset()。但是这里有个问题了,如果程序运行开始但是没有运行结束,如:抛出异常,程序直接报错,那又会怎么样呢?这里留到后面讲GC回收机制细说。

0x02 __sleep() & __wakeup()

这两个方法算是一对,而且在调用是出现的先后顺序比较重要

__sleep() 

PHP之魔术方法_第5张图片

 注意条件,是在序列化serialize()时检查是否有__sleep()并且是先执行sleep()再进行序列化

<划重点>

PHP之魔术方法_第6张图片

 先后关系就很明显了,甚至还可以和前面的__destruct()和__construct()比较先后调用的情况

__wakeup()

和__sleep()恰好相反,但进行反序列化时会检查__wakeup()方法是否存在,存在即先调用__wakeup()再进行反序列化

0x03 __get()& __set()

__get() :读取不可访问(protected 或 private)或不存在的属性的值时

__set():在给不可访问(protected 或 private)或不存在的属性赋值时(不常用)

PHP之魔术方法_第7张图片

 可以看到,因为类中没有b变量,所以当尝试调用b的时候会调用到__get()方法

0x04 __call()&__callStatic()

__call() : 在对象中调用一个不可访问或不存在的方法时,__call()会被调用

__callStatic() : 在静态上下文中调用一个不可访问或不存在的方法时,__callStatic会被调用(不常用)。

其实说白了和前面的__get()魔术方法类似,__get()是对变量而言,__call()是对函数而言。

PHP之魔术方法_第8张图片

$a->b为访问一个属性,$a->b()为访问一个函数,类中没有b()函数,所以就调用__call()方法,简单的哈哈哈。

0x05 __toStirng()

这里说的还是太保守了,当一个类被当作字符串时会有很多姿势

1)最常见的就是官方给的echo 打印时会调用__toString,当然打印也有print、print_r等等

2)反序列化对象与字符串进行比较(大多数为正则匹配),也可能是强比较(===)。不可能是弱比较,因为弱比较会先将非字符转换字符串(原因了解即可)。

3)反序列化对象与字符串连接时

4)在in_array()方法中,第一个参数为反序列化对象,第二个参数的数组中有tostring返回的字符串的时候tostring会被调用

小小总结:无论用了什么sao操作,只要最后会使得对象和字符串有关系的那么就会调用__toString()

0x06 __invoke()

当尝试以调用函数的方式调用一个对象时,该方法会被自动调用

这里需要注意,这个魔术方法只在PHP 5.3.0 及以上版本有效

这个方法调用挺简单,直接上图

PHP之魔术方法_第9张图片

 $a本应该是new_construct()对象,当使用$a()后相当于以调用函数的方式调用了对象,因此__invoke()就被调用了

三、总结

简述上述魔术方法触发条件如下:

__construct():创建对象时触发
__destruct() :对象被销毁时触发

__sleep() :在对象被序列化的过程中自动调用,且发生在序列化之前

__wakeup(): 该魔术方法在反序列化的时候自动调用,且发生在反序列化之前 

__get() :用于从不可访问或不存在的属性读取数据
__set() :用于将数据写入不可访问或不存在的属性

__call() :在对象上下文中调用不可访问的方法时触发
__callStatic() :在静态上下文中调用不可访问的方法时触发

__toString():在对象当做字符串的时候会被调用。

__invoke() :当尝试将对象调用为函数时触发

除了常见的以外,还有一些ctf不常见的魔术方法,仅当了解便可。

__isset():当对不可访问属性调用isset()或empty()时调用

__unset():当对不可访问属性调用unset()时被调用。

__set_state():调用var_export()导出类时,此静态方法会被调用。

__clone():当对象复制完成时调用

__isset() :在不可访问的属性上调用isset()或empty()触发
__unset() :在不可访问的属性上使用unset()时触发

你可能感兴趣的:(PHP反序列化,php,开发语言)