几个常见的PHP魔术方法
简单介绍
方法名 | 描述 |
---|---|
__sleep() | 执行序列化serialize()时,先会调用这个函数 |
__wakeup() | 执行反序列化unserialize()时,先会调用这个函数 |
__get() | 当获得一个类的成员变量时调用 |
__set() | 当设置一个类的成员变量时调用 |
__isset() | 当对不可访问属性调用isset()或empty()时调用 |
__unset() | 当对不可访问属性调用unset()时被调用。 |
__construct() | 类的构造函数 |
__destruct() | 类的析构函数 |
__call() | 在对象中调用一个不可访问方法时调用 |
__callStatic() | 用静态方式中调用一个不可访问方法时调用 |
__autoload() | 尝试加载未定义的类 |
__toString() | 在将一个对象转化成字符串时自动调用 |
详细介绍
__sleep()
当你使用一个序列化函数serialize()的时候,该函数会检查代码中是否存在__sleep()函数。一旦存在这个函数便会优先执行__sleep(),然后再去执行原来的序列化,serialize()找sleep(),但是sleep也控制着serialize()的返回值,把握着把柄呢。
此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。
注意点以及作用点:
__sleep() 不能返回父类的私有成员的名字。
__sleep() 方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。
Example
<?php
class Person
{
public $sex;
public $name;
public $age;
public function __construct($name="", $age=25, $sex='男')
{
$this->name = $name;
$this->age = $age;
$this->sex = $sex;
}
/**
* @return array
*/
public function __sleep() {
echo "当在类外部使用serialize()时会调用这里的__sleep()方法<br>";
$this->name = base64_encode($this->name);
return array('name', 'age'); // 这里必须返回一个数值,里边的元素表示返回的属性名称,这边控制只返回两个数值。
}
}
$person = new Person('1998'); // 初始赋值
echo serialize($person);
echo '<br/>';
输出结果:
当在类外部使用serialize()时会调用这里的__sleep()方法
O:6:“Person”:2:{s:4:“name”;s:8:“MTk5OA==”;s:3:“age”;i:25;}
__wakeup()
理解: 当进行unserialize()反序列化之后立即被调用
存在漏洞
当在反序列化字符串当中如果表示属性个数的值大于其真实值,则跳过该魔术方法
例如XCTF这题
class xctf{ //类
public $flag = '111';//public定义flag变量公开可见
public function __wakeup(){
exit('bad requests');
}
?code=
如果单纯构造:O:4:“xctf”:1:{s:4:“flag”;s:3:“111”;}
并不能绕过__wakeup()的执行
如果构造:O:4:“xctf”:2:{s:4:“flag”;s:3:“111”;} 便能绕过
__get()
书上是这样写的:
在程序运行过程中,在对象的外部获取私有成员的属性值,它有一个必要参数,即私有成员属性名,它返回一个允许对象在外部使用值。这个方法同样不需要主动调用,可以在方法前加上private关键字,防止用户直接调用
理解便是:
访问私有属性private、以及不存在的属性时被调用
__set()
书上是这样写的:
__set()方法:在程序运行过程中为私有的成员属性设置值,它不需要任何返回值。__set()方法包含两个参数,分别表示变量名称和变量值。两个参数不可省略,这个方法不需要主动调用,可以在方法前加上private关键字修饰,防止用户直接去调用。
理解便是:
__set( $property, $value )` 方法用来设置私有属性, 给一个未定义的属性赋值时,此方法会被触发,传递的参数是被设置的属性名和值。
Example
<?php
class Person
{
private $name;
private $age;
public function __construct($name="", $age=25)
{
$this->name = $name;
$this->age = $age;
}
/**
* 声明魔术方法需要两个参数,真接为私有属性赋值时自动调用,并可以屏蔽一些非法赋值
* @param $property
* @param $value
*/
public function __set($property, $value) {
if ($property=="age")
{
if ($value > 150 || $value < 0) {
return;
}
}
$this->$property = $value;
}
/**
* 在类中声明说话的方法,将所有的私有属性说出
*/
public function say(){
echo "我叫".$this->name.",今年".$this->age."岁了";
}
}
$Person=new Person("小明", 25); //注意,初始值将被下面所改变
//自动调用了__set()函数,将属性名name传给第一个参数,将属性值”李四”传给第二个参数
$Person->name = "小红"; //赋值成功。如果没有__set(),则出错。
//自动调用了__set()函数,将属性名age传给第一个参数,将属性值26传给第二个参数
$Person->age = 16; //赋值成功
$Person->age = 160; //160是一个非法值,赋值失效
$Person->say(); //输出:我叫小红,今年16岁了
输出结果:
我叫小红,今年16岁了
__isset()
理解:
用于检测变量是否存在,如果存在则返回true,否则返回false,用处便是为了对共有的成员属性进行检测,但不对私有的成员属性进行检测
__unset()
理解:
用于删除指定的变量,unset()函数可以对公有的成员属性进行删除操作,但是对于私有的成员属性还需依靠__unset()进行删除
Example:
void_unset(string name)
__construct()
php中构造方法是对象创建完成后第一个被对象自动调用的方法。在每个类中都有一个构造方法,如果没有显示地声明它,那么类中都会默认存在一个没有参数且内容为空的构造方法。
1、 构造方法的作用
通常构造方法被用来执行一些有用的初始化任务,如对成员属性在创建对象时赋予初始值。
2、 构造方法的在类中的声明格式
function __constrct([参数列表]){
方法体 //通常用来对成员属性进行初始化赋值
}
3、 在类中声明构造方法需要注意的事项
1、在同一个类中只能声明一个构造方法,原因是,PHP不支持构造函数重载。
2、构造方法名称是以两个下画线开始的__construct()
Example:
<?php
class Person
{
public $name;
public $age;
public $sex;
/**
* 显示声明一个构造方法且带参数
*/
public function __construct($name="", $sex="男", $age=22)
{
$this->name = $name;
$this->sex = $sex;
$this->age = $age;
}
/**
* say 方法
*/
public function say()
{
echo "我叫:" . $this->name . ",性别:" . $this->sex . ",年龄:" . $this->age;
}
}
$Person1 = new Person();
echo $Person1->say(); //输出:我叫:,性别:男,年龄:22
$Person2 = new Person("1998");
echo $Person2->say(); //输出:我叫:1998,性别:男,年龄:22
$Person3 = new Person("李四","男",25);
echo $Person3->say(); //输出:我叫:李四,性别:男,年龄:25
__destruct()
理解:
简称回收垃圾函数,当所有方法执行完成后被调用,当对象不能被访问时就会自动启动垃圾回收机制,收回对象占用的内存空间。而析构函数正是在垃圾回收机制回收对象之前调用的。
__call()
书面表达:
当程序试图调用不存在或不可见的成员方法时,PHP会先调用__call()方法来存储方法名以及其参数。__call()方法包含两个参数,即方法名和方法参数。其中,方法参数是以数组的形式存在的
理解便是
调用了不存在或不可见的成员方法(注意调用时需要给定两个参数,方法名以及方法参数,输出的便会是不存在的方法名以及以数组形式输出的方法参数)
__callStatic()
理解:
当调用的静态方法不存在或权限不足时自动触发该方法
注意与__call()的区别:
__call()
当对象访问不存在的方法时,__call()方法会被自动调用
__callStatic()
当对象访问不存在的静态方法时,__callStatic()方法会被自动调用
一般使用::调用静态类
__autoload()
书面表达
能够自动实例化需要使用的类,当程序要用到一个类,但该类还没有被实例化时,利用该方法便能自动查找和该类名称相同的文件
理解
单纯的导类必备魔术方法
__toString()
书面表达
当使用echo或者print输出对象时,将对象转化成字符串
Example
<?php
class people{
public function __toString(){
return "I am toString module";
}
}
$peo = new people();
echo $peo;
?>
输出
I am toString module
::的用法
外部调用类方法,或参数。只需要去找到::后面的方法即可,直接调用