上次做汇报时,被老师问到php的魔术方法,当时不清楚,其实之前也看过几次,但是都印象不深刻,所以写一篇博客来加深印象,也和大家分享一下。
首先明确魔术方法的定义,官方的定义是PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。
1.先来说一下构造函数。具有构造函数的类每次实例化的时候都会先调用构造函数。一个类实例化的过程,就是给类中的每个字段分配相应的内存空间,并分别赋予初值的过程,当一个类的字段很多,就用到了构造函数。所以构造函数很适合在使用对象之前,进行一些初始化的操作。php5.0以后,构造函数被统一命名为__construct。引用官方的例子:
<?php
class BaseClass {
function __construct() {
print "In BaseClass constructor\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "In SubClass constructor\n";
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass();
// In BaseClass constructor
$obj = new OtherSubClass();
?>
其运行结果是:。
parent::__construct();是用来干嘛的呢,当子类要继承父类时,并且父类和子类中都有构造函数时,并且要执行父类中的构造函数时,则需要parent::__construct();。
2.析构函数。类的对象在执行过程中,可能需要多个资源,如文件对象、数据库对象等、程序执行完毕后,如果不释放这些资源将会一直占有。这时,需要通过析构函数来清楚字段或者对象占有的资源。
什么情况下执行析构函数呢?php在对象销毁前执行这个函数(如:将变量赋值为null或者unset()对象)。实例如下:
<?php
class des{
function __destruct(){
echo "对象被销毁,执行析构函数<br>";
}
}
$p=new des(); /* 实例化类 */
echo "程序开始<br>";
$p = null; /* 变量赋值为null(或者销毁变量$p效果相同) */
echo "程序结束";
?>
执行结果为,
再来看下面一段代码:
<?php
class des{
public function test(){
echo "梦云智";
}
function __destruct(){
echo "运行结束,执行析构函数";
}
}
$p=new des(); /* 实例化类 */
$sum=0;
for($i=0;$i<10;$i++){
$sum=$sum+$i;
echo $sum;
}
echo "mengyunzhi"."<br>";
?>
执行结果为:为什么又执行了析构函数呢,是因为实例化对象之后,代码中没有对变量p销毁的代码,所以在析构函数在脚本关闭时调用。另外要注意的是,在析构函数中抛出异常会导致致命错误。
3.__get()和__set()是针对类中的属性,而__call()和__callStatic()是针对类中的方法的。
(1)__get和__set函数,__get函数是当我们想要调用类中不存在或者没有权限访问的属性时,php会默认的调用__get函数。__set函数是当我们给类中的不存在或者没有权限访问的属性新增或者赋值时,php会默认的调用__set函数。具体代码不再演示,可以参考老师的教程http://www.kancloud.cn/yunzhiclub/thinkphp5guide/169035。
(2)__call和__calStatic函数,对比__get函数,当我们想要调用类中不存在或者没有权限访问的方法时,php会默认的调用__call函数。代码如下:
<?php
class test{
// 调用不存在的方法时自动调用
public function __call($name,$arguments){
echo $name,'("',implode('","',$arguments),'")';
}
// 调用不存在的静态方法时自动通用
public static function __callStatic($name,$arguments){
echo $name.'("',implode('","',$arguments).'")';
}
<span style="white-space:pre"> </span>$t = new test();
$t->haha('PHP手册','hi-docs.com在线教程');
echo '<br/>';
test::hehe('JQUERY','选择器');</span>
}
输出结果:
haha("PHP手册","hi-docs.com在线教程")
hehe("JQUERY","选择器")
同理,当我们调用类中不存在或者没有权限访问的静态方法时,php会默认的调用__callStatic函数。
4.__isset和__unset函数
(1)在一个未定义的属性或者方法上调用isset()和empty()时,函数会自动调用,代码如下:
<?php
class Test
{
private $t1 = 't1';
public $t2 = 't2';
public function __isset($name)
{
echo $name.'未定义';
}
}
$test = new Test;
isset($test->demo);
isset($test->t1);
isset($test->t2);
?>
输出结果:
(2)在未定义的属性或者方法上调用unset()时,会自动调用__unset方法。代码如下:
<?php
class Test
{
private $t1 = 't1';
public $t2 = 't2';
public function __unset($name)
{
echo $name.'未定义';
}
}
$test = new Test;
unset($test->demo);
unset($test->t1);
unset($test->t2);
?>
输出结果:
5.魔术方法还有__sleep()、__wakeup()、__toString()、__invoke()、__clone()、__debugInfo()、__set_state__共15个方法,此处不再一一讲述了,有兴趣的可以自己查看资料。