1. 首页
  2. PHP

这是php编程法则?

php中常用的魔术方法

对于PHP开发者来说,掌握一些编程法则是十分重要的。而在PHP中,以双下划线(__)开头的方法称为魔术方法,它们扮演着非常重要的角色。

常用的魔术方法包括:

-__construct():类的构造方法;

-__destruct():类的析构方法;

-__call($funName, $arguments):当访问未定义或没有访问权限的方法时,__call()会被调用;

-__callStatic($funName, $arguments):当访问未定义或没有访问权限的静态方法时,__call()会被调用;

-__get($propertyName):读取类的成员变量时__get()会被调用;

-__set($property, $value):写入类的成员变量时__set()会被调用;

-__isset($content):当针对未定义或没有访问权限的成员使用isset()或empty()时__isset()会被调用;

-__unset($content):在未定义或没有访问权限的成员上使用reset()时__unset()会被调用;

-__sleep():在执行serialize()时__sleep()会被调用;

-__wakeup():在执行deserialization()时__wakeup()会被调用;

-__toString():使用echo方法直接输出对象时,__toString()会被调用;

-__invoke():像调用函数一样调用对象时,对象的__invoke()会被调用;

-__set_state($an_array):调用var_export()时__set_state()会被调用;

-__clone():复制对象时__clone()会被调用;

-__autoload($className):试图加载未定义的类;

-__debuginfo():输出调试信息。

本文将通过具体点的例子说明,这些PHP魔术方法的用法。

1) 析构方法的声明格式


注意:析构方法不能带任何参数。

2) 析构方法的用法

一般来说,PHP中析构方法并不是太常用。在类中它是可选的,通常用于在对象销毁之前执行某些清理工作。

下面的例子演示了如何使用析构方法:


以上程序的输出结果为:


3. __call()

该方法有两个参数。第一个参数$function_name自动接收未定义方法的名称,第二个参数$arguments以数组的方式接收该方法调用的多个参数。

1) __call()方法的用法


程序中调用未定义的方法时,__call()方法会自动被调用。

示例如下:


输出结果如下:


4. __callStatic()

当程序中调用未定义的静态方法时,__callStatic()方法会被调用。

__callStatic()的用法与__call()类似。示例如下:


输出结果如下:


 

 

5. __get()

当试图访问外部对象的私有属性时,程序会抛出异常并结束执行。但我们可以使用__get()方法来解决这个问题。它能在对象外部取得对象的私有方法。示例如下:


输出结果如下:


6. __set()

__set($property, $value) 方法用来设置对象的私有属性。当试图设置对象中未定义的属性时,就会触发__set()方法,调用参数为被设置的属性名和属性值。

示例代码如下:


下面是输出结果:


7. __isset()

在介绍__isset()方法之前,我先介绍下issset()方法。isset()方法主要用于判断某个变量是否被设置。

在对象外部使用isset()方法有两种情况:

  • 如果参数是公有属性,那么可以利用isset()方法判断属性是否被设置;
  • 如果参数是私有属性,isset()方法将无法使用。

那么,是否有办法判断私有属性被设置呢?当然,只需要在类里定义__isset()方法,就可以在对象外部利用isset()方法判断某个私有属性是否被设置了。

对未定义或没有权限访问的属性调用isset()或empty()时,就会调用__isset()方法。示例如下:


输出结果如下:


8. __unset()

与__isset()类似,在未定义或无权限访问的属性上调用unset()方法时会触发__unset()方法。示例如下:


输出结果如下:


9. __sleep()

serialize()方法会检查类中是否存在__sleep()魔术方法。如果存在,就会调用该方法来执行序列化操作。

__sleep()方法通常用来在保存数据之前指定哪些属性需要被序列化。如果对象中包含一些完全不需要序列化的巨大对象,__sleep()就能派上用场了。

具体用法请参考以下代码:


输出结果如下:


10. __wakeup()

与__sleep()方法相对的就是__wakeup()方法,常用来反序列化,如重建数据连接,或执行其他初始化操作等。

示例如下:


输出结果如下:


11. __toString()

使用echo方法直接输出对象时会调用其__toString()方法。

注意:该方法必须返回字符串,否则会抛出”E_RECOVERABLE_ERROR”级别的异常。在__toString()方法中也不能抛出异常。

示例如下:


返回结果如下:


如果类中没有定义__toString()会怎样?我们来试试看。


返回结果如下:


可见,它会在页面上报告致命错误,说明这种用法不允许。

12. __invoke()

当试图用调用函数的方式调用对象时,就会自动调用其__invoke()方法。

注意:该功能只在PHP 5.3.0以及以上版本上有效。

示例如下:


输出结果如下:


如果在未定义__invoke()方法的情况下将对象作为函数使用,就会得到以下的结果:


13. __set_state()

从PHP 5.1.0开始,__set_state()方法会在调用var_export()导出类代码时自动被调用。

__set_state()方法的参数是个数组,包含所有属性的值,格式为array(‘property’ => value, …)。

下面的示例中没有定义__set_state()方法:


输出结果如下:


可见,输出结果是对象的属性。

下面来看看如果定义了__set_state()方法会怎样:


输出结果如下:


14. __clone()

PHP中可以使用clone关键字来复制对象,其格式如下:


但是,clone关键字只会进行浅复制,所有引用的属性依然会指向原来的变量。

如果对象里定义了__clone()方法,那么复制时就会调用__clone()方法,从而允许我们修改被复制的值(如果需要的话)。

示例如下:


输出结果如下:


15. __autoload()

__autoload()方法可以尝试加载未定义的类。

以前,如果在整个程序的生命周期内创建100个对象,就要用include()或require()包含100个类文件,或者在同一个类文件内定义100个类,例如:


那么使用__autoload()方法呢?


当PHP引擎第一次使用类A时,如果A没有找到,就会调用__autoload方法,参数为类名”A”。然后我们需要在__autoload()方法中根据类名找到相应的类文件并包含该文件。如果文件没有找到,PHP引擎就会抛出异常。

16. __debugInfo()

执行var_dump()方法的时候会调用__debugInfo()方法。如果__debugInfo()没有定义,则var_dump()方法会输出对象中的所有属性。

示例如下:


输出结果如下:


注意:__debugInfo()方法只能用于PHP 5.6.0及更高版本。

END

原创文章,作者:calvin chan,如若转载,请注明出处:https://www.calvinyuki.com/209.html