什么是魔法方法

PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。所以在定义类方法时,除了上述魔术方法,建议不要以 __为前缀。
魔法方法是不显示的调用而是由某种特定的条件出发的
下面是官方给出来的说明和使用的魔法方法
https://www.php.net/manual/zh/language.oop5.magic.php

__construct魔法方法

__construct类会在每次创建新对象时先调用此方法
所以非常适合在使用对象之前做一些初始化工作
简单理解就是__construct会在类里面自动执行
列如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
class Site {
//公用变量
public $url;

//公用方法里面接受传参
function __construct($url){
//赋值给$url变量,可以说是初始化
$this->url=$url;
}

function Siteurl(){
//输出被初始化的内容
echo $this->url;

}
}

$url="aaaaa";

//实例化该类的对象传参
$a= new Site($url);

//输出Siteurl()函数
$a->Siteurl();

结果

__sleep()和__wakeup()魔法方法

__sleep()__wakeup()其实是一样的就是被调用的函数不一样
serialize()函数会检查类中是否存在一个魔术方法 __sleep(),如果存在,该方法会先被调用
unserialize()函数会检查类中是否存在一个魔术方法 __wakeup(),如果存在,该方法会先被调用

__sleep()魔法方法实咧

serialize()函数会检查类中是否存在一个魔术方法 __sleep(),如果存在,该方法会先被调用,然后才执行序列化操作
此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误

注意
__sleep() 不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。

用于
方法常用于提交未提交的数据,或类似的清理操作。同时,如果有一些很大的对象,但不需要全部保存,这个功能就很好用。

实咧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class Site {
//公用变量
public $url="aaa";
//公用变量
public $url2="bbb";
//公用变量
public $url3="ccc";
//定义__sleep魔法方法
function __sleep(){
echo "你好";

//序列化时只会存储 url 不会被序列化,表示返回的属性名
return ['url'];
}
}
//实例化该类的对象
$a= new Site($url);

//输出返回的属性名
echo serialize($a);

结果:

如果我把__sleep()里面的内容注释掉他会返回什么
代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class Site {
//公用变量
public $url="aaa";
//公用变量
public $url2="bbb";
//公用变量
public $url3="ccc";
//定义__sleep魔法方法
function __sleep(){
//echo "你好";

//序列化时只会存储 url 不会被序列化,表示返回的属性名
//return ['url'];
}
}
//实例化该类的对象
$a= new Site();

//输出返回的属性名
echo serialize($a);

结果

__wakeup()魔法方法实咧

unserialize()才会触发__wakeup()魔法方法
unserialize()函数会检查类中是否存在一个魔术方法 __wakeup(),如果存在,该方法会先被调用

他和__sleep()是一样的

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class Site {
//公用变量
public $url="aaa";
//定义__sleep魔法方法
function __wakeup(){
echo "不好";

}
}
//实例化该类的对象
$a= new Site();
echo unserialize(serialize($a));

结果

__destruct()魔法方法

__destruct()这个函数在对象被销毁前会被执行
下面参数会用到unset()函数,他是删除销毁一个变量函数等等
咧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
class Site {
//公用变量
public $url="aaa";
//定义方法
function Siteurl(){
echo "不好";
}
//定义一个__destruct()魔法方法
function __destruct(){
echo "好";
}
}
//实例化该类的对象
$a= new Site();

//删除实例化该类的对象
unset($a);

结果

__toString()魔法方法

__toString()用于一个类被当成字符串时应怎样回应,
通俗简单来说就是叫一个对象用输出的函数当做字符串来输出
注意
此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误
这个通俗的来讲就是如果没有__toString()直接输出对象就会报错
列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class Site {
//公用变量
public $url="aaa";
//定义方法
function Siteurl(){
echo "不好";
}
//定义一个__toString()魔法方法
function __toString(){
return $this->url;
}
}
//实例化该类的对象
$a= new Site();
//当做一个字符串来使用
echo $a;

结果

如果我不用__toString()会怎么样下面我就测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class Site {
//公用变量
public $url="aaa";
//定义魔法方法
function Siteurl(){
echo "不好";
}

}
//实例化该类的对象
$a= new Site();
//当做一个字符串来使用
echo $a;

结果他就报错了

__call()魔法方法

当调用当前环境下未定义或不可见的类属性或方法时,重载方法会被调用__call()
在给不可访问属性赋值时,__set() 会被调用。
读取不可访问属性的值时,__get() 会被调用。
等等

通俗来说就是你访问一个对象中没有的东西就会调用__call()

作用
为了避免当调用的方法不存在时产生错误,而意外的导致程序中止,可以使用 __call() 方法来避免。

__call($a,$b)他有两个参数,也可以不带
$a,就是你调用一个对象里面没有的属性的名,那么$a就是属性的名
$b,就是你调用一个对象里面没有的属性的名,并传递参数那这个$b就是被传的参数,应为参数很多$b就是一个数组

下面访问一个对象里面不存在的属性和方法,__call()就会被执行
咧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class Site {
//公用变量
public $url="aaa";
//定义方法
function Siteurl(){
echo $this->url;
}

//如果调用一个不存在的内容就会执行下面的__call方法
function __call($funName, $arguments){
echo "没有这个".$funName."<br>";

echo "这个是你输入的猜数";
print_r($arguments);
}

}
//实例化该类的对象
$a= new Site();

// 调用对象中不存在的方法,则自动调用了对象中的__call()方法
$a->run("aaaa");

结果

下面访问一个对象里面不存在的方法,__call()就不会被执行
咧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
class Site {
//公用变量
public $url="aaa";
//定义方法
function Siteurl(){
echo $this->url;
}

//如果调用一个不存在的内容就会执行下面的__call方法
function __call($funName, $arguments){
echo "没有这个".$funName."<br>";

echo "这个是你输入的猜数";
print_r($arguments);
}

}
//实例化该类的对象
$a= new Site();

//调用对象中存在的方法,则__call()方法不会被调用
$a->Siteurl();

结果

__callStatic魔法方法

__callStatic方法在调用对象静态方法不存在的时候被调用

__callStatic__call()是一样的
__call()就是一个是访问普通的类内容不存在会被调用
__callStatic方法在调用对象静态方法不存在的时候被调用

作用
为了避免当调用的静态方法不存在时产生错误,而意外的导致程序中止,可以使用 __callStatic 方法来避免。

__callStatic($a,$b)他有两个参数,也可以不带
$a,就是你调用一个对象里面没有的属性的名,那么$a就是属性的名
$b,就是你调用一个对象里面没有的属性的名,并传递参数那这个$b就是被传的参数,应为参数很多$b就是一个数组

咧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
class Site {
//公用变量
public $url="aaa";
//定义方法
function Siteurl(){
echo $this->url;
}

//如果调用一个不存在的内容就会执行下面的__callStatic方法
function __callStatic($funName, $arguments){
echo "没有这个静态".$funName."<br>";
echo "这个是你输入的猜数";
print_r($arguments);
}

}
//调用对象中存在的方法
Site::aaaa("ccccc")

结果

__get()魔法方法

类的成员属性被设定为 private 后,如果我们试图在外面调用它则会出现“不能访问某个私有属性”的错误。那么为了解决这个问题,我们可以使用魔术方法 __get()

用于
在程序运行过程中,通过它可以在对象的外部获取私有成员属性的值。

__get($a)他有一个参数
$a 参数传入你要获取的成员属性的名称,返回获取的属性值

咧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
class Site {
//私有属性
private $url="aaa";

//定义方法
function Siteurl(){
echo $this->url;
}

//如果调用一个private的属性就会执行下面的__get方法
function __get($arguments){
echo "没有这个".$arguments;
}

}
//实例化该类的对象
$a= new Site("abcd");

//访问一个私有属性
echo $a->url;

结果

__set魔法方法

在类外赋值一个类内的私有属性和给一个未定义的属性赋值时,此方法会被触发
简单来说就是你放一个私有的或者给他赋值或者没有这个属性,此方法会被触发

__set($a,$b)他有两个参数,也可以不带
$a,就是你调用一个对象里面没有的属性的名,那么$a就是属性的名
$b,就是你调用一个对象里面没有的属性的名,并传递参数那这个$b就是被传的参数,应为参数很多$b就是一个数组

咧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class Site {
//私有属性
private $url="aaa";

//定义方法
function Siteurl(){
echo $this->url;
}

//如果赋值一个private访问不了就会执行下面的__get方法
function __set($funName,$arguments){
echo "你没有或不能访问".$funName;
echo "不赋值".$arguments;
}

}
//实例化该类的对象
$a= new Site("abcd");

//给一个私有属性赋值
echo $a->url="aaaaa";

结果