PHP魔术方法笔记

前言

在 PHP 中,以双下划线__开始命名的方法被称作 PHP 中的魔术方法,它们在 PHP 中充当很重要的角色。

常见的魔术方法有:

__construct():构造函数
__destruct():析构函数
__get(): 访问不存在的成员变量时调用
__set():设置不存在的成员变量时调用
__call():调用一个对象中不存在或被权限控制中的方法时,__call()将被调用。
__callStatic():调用一个对象中不存在或被权限控制中的静态方法时,__callStatic()将被调用。
__isset():用isset或empty检测一个对象的属性是否设置并且这个属性不存在(或被权限控制)时会自动调用__isset()方法
__unset():当调用reset()对一个未定义或不可达的成员更新时,__unset()方法将被调用
__slepp():当执行serialize()时,__slepp()方法将首先被调用。
__wakeup():当执行unserialize()方法时,__wakeup()将首先被调用。
__toString():将一个对象当作字符串来使用时__toString()方法将首先被调用。
__invoke():使用调用函数访问一个对象时,__invoke()将被调用。
__clone():当对象被复制完成时,__clone()将被调用

构造函数__construct()

当类被实例化的时候自动调用

<?php
class Test{
    public function __construct()
    {
        echo 'izero 761202280';
    }
}
$t = new Test; 
// 输出:izero 761202280

析构函数:__destruct()

在对象销毁时调用

<?php
class Test{
    public function __destruct()
    {
        echo 'izero 761202280';
    }
}
$t = new Test; 
unset($t); // 销毁对象
// 输出:izero 761202280

__get() 与 __set()

__get(): 访问不存在的成员变量时调用
__set():设置不存在的成员变量时调用

// __get()
<?php
class Test{
    private $age;
    public function __construct($age)
    {
        $this->age = $age;
    }

    public function __get($name)
    {
        echo '进入__get----';
        if ($name == "age")
        {
            return 0;
        }
    }
}
$t = new Test(18);
echo "年龄:".$t->age;
echo $t->test; // 读取一个不存在的属性
// 输出:
进入__get----年龄:0
进入__get----

// __set()

<?php
class Test{
    private $age;
    public function __construct($age)
    {
        $this->age = $age;
    }
    public function __set($name, $value)
    {
        $this->$name = $value;
        echo "进入__set:$name = $value";
    }
}
$t = new Test(18);
$t->test = 'test1';
// 输出:进入__set:test = test1

__call() 与 __callStatic

__call():调用一个对象中不存在或被权限控制中的方法时,__call()将被调用。
__callStatic():调用一个对象中不存在或被权限控制中的静态方法时,__callStatic()将被调用。

<?php
header("Content-Type: text/html; charset=utf-8");
class Test1{
    // $name : 名称
    // $arguments : 参数
    public function __call($name, $arguments)
    {
        echo '自动调用了__call方法:<br />';
        echo "$name = $arguments<br />";
    }
    public static function __callStatic($name, $arguments)
    {
        echo '自动调用__callStatic方法:<br />';
        echo "$name = $arguments<br />";
    }
    private function test(){
        echo 'test() ';
    }
}
$t = new Test1;
$t->test(123); // 调用一个私有方法
$t->test2("hello"); // 调用一个不存在的方法
$t::test3(); // 静态调用了一个不存在的方法

/*
输出:
自动调用了__call方法:
test = Array
自动调用了__call方法:
test2 = Array
自动调用__callStatic方法:
test3 = Array
*/

__isset()

用isset或empty检测一个对象的属性是否设置并且这个属性不存在(或被权限控制)时会自动调用__isset()方法

<?php
class Test1{
    public function __isset($name)
    {
        echo "自动调用了__isset方法:$name<br />";
    }
}
$t = new Test1;
isset($t->age);
isset($t->a);
empty($t->age);
empty($t->b);

/*
输出:
自动调用了__isset方法:a
自动调用了__isset方法:b
*/

__unset()

当调用reset()对一个未定义或不可达的成员更新时,__unset()方法将被调用

<?php
header("Content-Type: text/html; charset=utf-8");
class Test1{
    public $age;
    private $b;
    public function __unset($name)
    {
        echo "自动调用了__unset方法:$name<br />";
    }
}
$t = new Test1;

unset($t->a);
unset($t->age);
unset($t->b);

/*
输出:
自动调用了__unset方法:a
自动调用了__unset方法:b
*/

__slepp()

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

对象被序列化之前触发,返回需要被序列化存储的成员属性,删除不必要的属性。

代码示例:

<?php

class User{
    public $username;
    public $password;

    public function __sleep()
    {
        return array('username');
    }
}

$user = new User();
$user->username = "admin";
$user->password = "admin";

var_dump(serialize($user));

// 输出:string(42) "O:4:"User":1:{s:8:"username";s:5:"admin";}"
// 输出的结果很显然序列化的时候忽略了 password 字段的值。

__wakeup()

unserialize会检查是否存在一个__wakeup()方法。如果存在,则会先调用 __wakeup()方法,预先准备对象需要的资源。 预先准备对象资源,返回void,常用于反序列化操作中重新建立数据库连接或执行其他初始化操作。

代码示例:

<?php

class User{
    public $username;
    public $password;

    function __wakeup(): void
    {
        $this->password = $this->username;
    }
}

var_dump(unserialize('O:4:"User":1:{s:8:"username";s:5:"admin";}'));

/*
输出
object(User)#1 (2) {
  ["username"]=>
  string(5) "admin"
  ["password"]=>
  string(5) "admin"
}
*/

__toString()

将一个对象当作字符串来使用时,如:字符串输出、字符串连接、相等比较、经过php字符串函数:strlen()、addslashes()等,会自动调用该方法。如echo $obj;
此方法必须返回一个字符串,否则将发出一条 E_RECOVERABLE_ERROR 级别的致命错误。

<?php
header("Content-Type: text/html; charset=utf-8");
class Test1{
    public function __toString()
    {
        echo '自动调用了__toString()方法<br />';
        return "";
    }
}
$t = new Test1;
echo $t;
/*
输出:
自动调用了__toString()方法
*/

__invoke()

使用调用函数访问一个对象时,__invoke()将被调用。

<?php
header("Content-Type: text/html; charset=utf-8");
class Test1{
    public function __invoke()
    {
        echo '自动调用了__invoke()方法<br />';
    }

}
$t = new Test1;
$t();
/*
输出:
自动调用了__invoke()方法
*/

__clone()

当对象被复制完成时,__clone()将被调用

<?php
header("Content-Type: text/html; charset=utf-8");
class Test1{
    public function __clone()
    {
        echo '__clone方法自动调用';
    }
}
$t = new Test1;
$t2 = clone $t; // clone 克隆对象
/*
输出:
__clone方法自动调用
*/
posted @ 2023-05-15 17:59  iZero  阅读(14)  评论(0编辑  收藏  举报