__construct(),__destruct(),__get(),__set(),__isset(),__unset(),__clone()等方法在PHP中被称为“魔术方法”。在命名自己的类方法时不能使用这些方法名,除非想使用其魔术功能。

__construct()与__destruct()

  • __construct 构造方法,是一个在对象被“创建”的时候,会自动调用的方法;
  • __destruct 析构方法,是一个在对象被“销毁”的时候,会自动调用的方法;
  • 构造方法不是用来创建对象的;
  • 析构方法不是用来销毁对象的;
<?php

class  A
{
    public $name = 'tom';
    //构造方法的作用:
    //是给予我们一个“机会”,让我们在实例化一个对象的时候(new的时候),
    //能够去做一些这个时刻需要的“初始化工作”——通常就是在此时可以给该实例
    //化出来的对象的属性赋初值——即“对象初始化”;
    function __construct()
    {
        echo 'hei world!' . '<br>';
    }


    //析构方法的作用:
    //一般都没什么用!——php早就已经对绝大多数资源(数据)实现了
    //自动回收(清理)机制。但是,它给我们一个“机会”,让我们可以
    //在一个对象被销毁的时候,有时机去做一些可能需要做的“清理工作”。
    function __destruct()
    {
        // TODO: Implement __destruct() method.
        echo $this->name . '销毁了' . '<br>';
    }
}

$cc = new  A(); //hei world!  //tom被销毁了

__get()与__set()

  • __get($property)当调用一个未定义的属性或没有声明的属性时调用此方法。
  • __set($property,$value)给一个未定义的属性或没有声明的属性赋值时调用此方法。
  • 这里的没有声明包括当使用对象调用时,访问控制修饰符为protected或private的属性(即没有权限访问的属性)。
<?php

class Person
{
    public $name = 'tom';
    private $money = 1234;
    protected $sex = 'man';

    function __get($name)
    {
        // TODO: Implement __get() method.
        echo '获取未定义或没有声明的属性(没有权限访问的属性)的 ' . $name . '值 <br>';
    }

    function __set($name, $value)
    {
        // TODO: Implement __set() method.
        echo '你想设置属性 ' . $name . ' 的值为 ' . $value . '<br>';
    }
}

$cc = new Person();
echo $cc->name . '<br>';//tom
//__get
echo $cc->age . '<br>';//未定义 //获取未定义或没有声明的属性(没有权限访问的属性)的 age值
echo $cc->money . '<br>';//没有访问权限 //获取未定义或没有声明的属性(没有权限访问的属性)的 money值
echo $cc->sex . '<br>';//没有访问权限 //获取未定义或没有声明的属性(没有权限访问的属性)的 sex值
//__set
$cc->age = 22 . '<br>';//未定义 //你想设置属性 age 的值为 22
$cc->money = 90000 . '<br>';//没有访问权限 //你想设置属性 money 的值为 90000
$cc->sex = 'woman' . '<br>';//没有访问权限 //你想设置属性 sex 的值为 woman

__isset()与_unset()

  • __isset($property)当对一个未定义的属性或没有声明的属性调用isset()函数时调用此方法
  • __unset($property)当对一个未定义的属性或没有声明的属性调用unset()函数时调用此方法与__get方法和__set方法相同,这里的没有声明的属性包括当使用对象调用时,访问控制修饰符为protected或private的属性(即没有权限访问的属性)
<?php

class Person
{
    public $name = 'tom';
    private $money = 1234;
    protected $sex = 'man';

    function __isset($name)
    {
        // TODO: Implement __isset() method.
        echo '__isset被调用了' . '<br>';
    }

    function __unset($name)
    {
        // TODO: Implement __unset() method.
        echo '__unset被调用了' . '<br>';
    }
}
$cc = new Person();

isset($cc->name);
isset($cc->age);//__isset被调用了
isset($cc->sex);//__isset被调用了

unset($cc->name);
unset($cc->age);//__unset被调用了
unset($cc->sex);//__unset被调用了

__clone()

  • PHP中的对象赋值是使用的引用赋值,如果想复制一个对象则需要使用clone方法,在调用此方法时对象会自动调用__clone魔术方法。

__toString()

  • __toString方法在将一个对象转化成字符串时自动调用,比如使用echo打印对象时如果类没有实现此方法,则无法通过echo打印对象,否则报错。
  • 此方法必须返回一个字符串
<?php

class Person
{
    public $name = 'Lucy';

    public function __construct($name = '')
    {
        if ($name !== '') {
            $this->name = $name;
        }
    }

    public function __clone()
    {
        // TODO: Implement __clone() method.
        echo '有Person对象被克隆了' . '<br>';
    }

    function __toString()
    {
        // TODO: Implement __toString() method.
        //echo '这是一个Person类的对象';//echo 不行 而是 return 一个字符串
        return '这是一个Person类的对象' . $this->name . '<br>';
    }
}

$cc = new Person();
$cc1 = clone $cc;//有Person对象被克隆了
$cc2 = clone $cc;//有Person对象被克隆了

//echo $cc;//若无toString则报错:Object of class Person could not be converted to string
echo $cc;//这是一个Person类的对象Lucy

//应用:调试对象
$tom = new Person('Tom');
echo $tom;//这是一个Person类的对象Tom
$lucy = new Person();
echo $lucy;//这是一个Person类的对象Lucy

__sleep()与__wakeup

  • __sleep()在对象被serialize之前被调用。若对象比较大,想删减一点点东西再序列化,可考虑一下此函数。返回值是包含这个对象需要序列化的属性数组。
  • __wakeup()在对象被unserialize时被调用,常用于做一些对象的初始化工作。

__invoke()

  • 当尝试以调用函数的方式调用一个对象时,__invoke方法会被自动调用。
<?php

class Person
{
    public $name = 'Lucy';
    private $age = 22;
    private $money = 1000;

    function __sleep()
    {
        // TODO: Implement __sleep() method.
        echo '有对象被序列化了<br>';
        //return null;//报错
        return array('name', 'age', 'money');
    }

    function __wakeup()
    {
        // TODO: Implement __wakeup() method.
        echo '<br>有对象被反序列化了<br>';
        //初始化动作
        $this->test();
    }

    function test()
    {
        //实现一些类的初始化,比如:链接数据库,根据类的属性值来做一些初始化工作
        echo '做一些初始工作<br>';
    }

    function __invoke($a)
    {
        // TODO: Implement __invoke() method.
        var_dump($a);
    }
}

$cc = new Person();
//序列化对象
$a = serialize($cc);//有对象被序列化了
print_r($a);//O:6:"Person":3:{s:4:"name";s:4:"Lucy";s:11:"Personage";i:22;s:13:"Personmoney";i:1000;}

//反序列化对象
$cc = unserialize($a);//有对象被反序列化了 //做一些初始工作
print_r($a);//O:6:"Person":3:{s:4:"name";s:4:"Lucy";s:11:"Personage";i:22;s:13:"Personmoney";i:1000;}

$cc(1);//int 1

__call($method,$arg);

  • 当调用一个未定义的方法时调用此方法,这里的未定义的方法包括没有访问权限的方法。

__callStatic();

  • 它的工作方式类似于__call()魔术方法,__callStatic是为了处理静态方法调用,并且必须被声明为静态的。
<?php

class Person{
    function test(){
        echo '测试方法<br>';
    }
    function __call($name, $arguments)
    {
        // TODO: Implement __call() method.
        echo '你试图调用一个不存在的方法: '.$name.'<br>';
        echo '传递的参数是:';
        print_r($arguments);
    }
    static function __callStatic($name, $arguments)
    {//必须申明为静态的
        // TODO: Implement __callStatic() method.
        echo '你试图调用一个不存在的方法: '.$name.'<br>';
        echo '传递的参数是:';
        print_r($arguments);
    }
}
$cc=new Person();

//__call
$cc->test();//测试方法
$cc->test2(1,2,3,4);
/*你试图调用一个不存在的方法: test2
传递的参数是:Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 )*/

//__callStatic
Person::test2(1,2,3);
/*你试图调用一个不存在的方法: test2
传递的参数是:Array ( [0] => 1 [1] => 2 [2] => 3 )*/

__autoload();

  • 它会在试图使用尚未被定义的类时自动调用。通过调用此函数,脚本引擎在 PHP 出错失败前有了最后一个机会加载所需的类。
<?php

class T
{
    function tt()
    {
        echo 'tt<br>';
    }
}

function __autoload($className)
{
    echo '你想使用一个没有申明的类' . $className . '<br>';
    //判断是否有其他定义这个 $className 的类,如果没有,
    //提示一个友好的错误信息,之后通过include引入新的文件弥补错误
    include 'url.php';//引入的文件弥补缺失的类
}

$t = new T();
$t->tt();

$tt = new Tt();//实例 缺失的类
10-07 16:56