PHP魔术方法

Caution
PHP 将所有以 __(两个下划线)开头的类方法保留为魔术方法。


1. 构造函数 __construct()

PHP构造函数是对象创建完成后,第一个被对象自动调用的方法;每个类中都默认有一个构造方法,如果没有显式地声明它,那么类中都会默认存在一个没有参数且内容为空的构造方法。

如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。

1.1. 构造函数的作用

主要用于类中数据的初始化,可以通过传入参数初始化成员变量,或者设定成员变量的初始值。在项目中,一般用于初始化变量或者做权限的校验。
需要注意的是,同一个类中,只允许一个构造函数,因为PHP不支持函数重载,但是继承时,子类构造函数可以覆盖父类构造函数。


2. 析构函数 __destruct()

PHP析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。析构函数与构造函数不同,它不接受任何参数。

和构造函数一样,父类的析构函数不会被引擎暗中调用。要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。此外也和构造函数一样,子类如果自己没有定义析构函数则会继承父类的。

析构函数即使在使用 exit() 终止脚本运行时也会被调用。在析构函数中调用 exit() 将会中止其余关闭操作的运行。

2.1. 析构函数的作用

在PHP项目中,析构函数使用场景并不太多,一般都用于:

  • 数据库类中释放查询&关闭数据库连接
  • 图像类中销毁图像资源
  • FTP类中断开端口FTP连接

3. 方法重载 __call() & __callStatic()

3.1. public mixed __call (string $method, array $arguments)

为了避免当调用的方法不存在时产生错误,而意外的导致程序中止,可以使用 __call() 方法来避免。该方法在调用的方法不存在时会自动调用,程序仍会继续执行下去

在PHP项目中,一般用于:

  • 方法调用发生异常后 引导到__call方法处理
  • 利用__call方法重载 实现一些特殊的Model方法 (魔术方法)
3.2. public static mixed __callStatic (string $method, array $arguments)

在静态上下文中调用一个不可访问方法时,__callStatic() 会被调用。该方法功能,除了是为静态方法准备的以外,别的与 __call()一样。


4. 属性重载 __set() & __get() & __isset() & __unset()

4.1. public void __set (string $name, mixed $value)

在给不可访问属性赋值时,__set() 会被调用,主要可以用于给私有属性赋值时,屏蔽一些非法赋值。

4.2. public mixed __get (string $name)

获得一个类的成员变量时调用,类的成员属性被设定为 private 后,如果我们试图在外面调用它则会出现“不能访问某个私有属性”的错误,这个时候就可以使用__get()方法,从外部调用私有变量。此方法可以再获取值的同时,对该值进行一些业务逻辑上的处理。

4.3. public bool __isset (string $name)

当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用。
如果对象里面成员是公有的,可以直接使用 isset() 函数。如果是私有的成员属性,那就需要在类里面加上一个 __isset() 方法。

4.4. public void __unset (string $name)

当对不可访问属性调用 unset() 时,__unset() 会被调用。
同 isset() 函数一样,unset() 函数只能删除对象的公有成员属性,当要删除对象内部的私有成员属性时,需要使用__unset() 方法。


5. 序列化与反序列化 __sleep() & __wakeup()

5.1. public array __sleep (void)

当使用serialize() 方法直接序列化某个时,函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,返回一个包含对象中所有应被序列化的变量名称的数组,然后才执行序列化操作。

Note
不能返回父类的私有成员的名字。这样做会产生一个 E_NOTICE 级别的错误。可以用 Serializable 接口来替代。
如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误。

在项目中,如果需要序列化某个类却不需要序列化该类中所有的属性时,则需要定义该方法,用于清理对象。或者序列化对象时,某些值需要加密后序列化,则可以在该函数中做相应处理逻辑。

5.2. void __wakeup (void)

与 __sleep() 相反,__wakeup() 作用于unserialize() 某个类之前,预先准备对象需要的资源,例如重新建立数据库连接,或执行其它初始化操作,解密序列化之前加密的数据等。


6. __toString() 类变字符串

将一个对象当做一个字符串来使用时,会自动调用该方法,并且在该方法中,可以返回一定的字符串,以表明该对象转换为字符串之后的结果。
该魔术方法经常用于测试时,在__toString() 中,将需要展示的类属性格式化,通过echo 该类直接输出展示。

Warning
不能在 __toString() 方法中抛出异常。这么做会导致致命错误。


7. __invoke() 类变函数

该魔术方法会在将一个对象作为函数调用时被调用,目前来说,遇到的项目暂时没见过使用这个方法去处理逻辑或业务场景的情况,具体用途方面,欢迎各位遇到的朋友补充告知。


8. __set_state() 导出类

当调用 var_export() 导出类时,此静态方法会被调用。
在一般项目中,可以用于使用var_export() 生成配置文件前,作一些逻辑上的处理,使用场景并不太多。

var_export()
此函数多用于用户生成配置文件,此函数返回关于传递给该函数的变量的结构信息,它和 var_dump() 类似,不同的是其返回的表示是合法的 PHP 代码。


9. __clone() 对象复制

解释此方法的运用,首先要知道clone 对象的用处:

class testClass
{
    public $attr1;
    public $attr2;
}

$obj = new testClass();
$obj -> attr1 = 'a';
$obj -> attr2 = 'b';

$copyObj = $obj;
## 使用关键字clone可以完成对对象的复制 ##
$cloneObj = clone $obj;

$copyObj->attr1 = 'new a';

print_r($obj);
print_r($copyObj);
print_r($cloneObj);

打印结果:

Shop\Controller\testClass Object
(
    [attr1] => new a
    [attr2] => b
)
Shop\Controller\testClass Object
(
    [attr1] => new a
    [attr2] => b
)
Shop\Controller\testClass Object
(
    [attr1] => a
    [attr2] => b
)

实例化对象后的赋值引用赋值,使用关键字clone可以完成对对象的复制得到新的独立的对象。

当复制完成时,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy),如果定义了 __clone() 方法,则新创建的对象(复制生成的对象)中的 __clone() 方法会被调用,该方法在一般项目中的用途:

  • 在__clone() 方法中执行深度复制(deep clone);
  • 复制时过滤或者修改某些值;
  • 限制某些对象的复制。

10. __debuginfo() 调试打印

var_dump()一个类时的回应,返回一个包含对象属性的数组,目前来说,遇到的项目暂时没见过使用这个方法去处理逻辑或业务场景的情况,具体用途方面,欢迎各位遇到的朋友补充告知。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枫叶Fy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值