详解php魔术方法(Magic methods)的使用方法


Posted in PHP onFebruary 14, 2016

PHP中把以两个下划线__开头的方法称为魔术方法,这些方法在PHP中充当了举足轻重的作用。 魔术方法包括:

  • __construct(),类的构造函数
  • __destruct(),类的析构函数
  • __call(),在对象中调用一个不可访问方法时调用
  • __callStatic(),用静态方式中调用一个不可访问方法时调用
  • __get(),获得一个类的成员变量时调用
  • __set(),设置一个类的成员变量时调用
  • __isset(),当对不可访问属性调用isset()或empty()时调用
  • __unset(),当对不可访问属性调用unset()时被调用。
  • __sleep(),执行serialize()时,先会调用这个函数
  • __wakeup(),执行unserialize()时,先会调用这个函数
  • __toString(),类被当成字符串时的回应方法
  • __invoke(),调用函数的方式调用一个对象时的回应方法
  • __set_state(),调用var_export()导出类时,此静态方法会被调用。
  • __clone(),当对象复制完成时调用

__construct()和__destruct()

构造函数和析构函数应该不陌生,他们在对象创建和消亡时被调用。例如我们需要打开一个文件,在对象创建时打开,对象消亡时关闭

<?php 
class FileRead
{
 protected $handle = NULL;

 function __construct(){
  $this->handle = fopen(...);
 }

 function __destruct(){
  fclose($this->handle);
 }
}
?>

这两个方法在继承时可以扩展,例如:

<?php 
class TmpFileRead extends FileRead
{
 function __construct(){
  parent::__construct();
 }

 function __destruct(){
  parent::__destruct();
 }
}
?>

__call()和__callStatic()

在对象中调用一个不可访问方法时会调用这两个方法,后者为静态方法。这两个方法我们在可变方法(Variable functions)调用中可能会用到。

<?php
class MethodTest 
{
 public function __call ($name, $arguments) {
  echo "Calling object method '$name' ". implode(', ', $arguments). "\n";
 }

 public static function __callStatic ($name, $arguments) {
  echo "Calling static method '$name' ". implode(', ', $arguments). "\n";
 }
}

$obj = new MethodTest;
$obj->runTest('in object context');
MethodTest::runTest('in static context');
?>

__get(),__set(),__isset()和__unset()

当get/set一个类的成员变量时调用这两个函数。例如我们将对象变量保存在另外一个数组中,而不是对象本身的成员变量

<?php 
class MethodTest
{
 private $data = array();

 public function __set($name, $value){
  $this->data[$name] = $value;
 }

 public function __get($name){
  if(array_key_exists($name, $this->data))
   return $this->data[$name];
  return NULL;
 }

 public function __isset($name){
  return isset($this->data[$name])
 }

 public function unset($name){
  unset($this->data[$name]);
 }
}
?>

__sleep()和__wakeup()

当我们在执行serialize()和unserialize()时,会先调用这两个函数。例如我们在序列化一个对象时,这个对象有一个数据库链接,想要在反序列化中恢复链接状态,则可以通过重构这两个函数来实现链接的恢复。例子如下:

<?php
class Connection 
{
 protected $link;
 private $server, $username, $password, $db;

 public function __construct($server, $username, $password, $db)
 {
  $this->server = $server;
  $this->username = $username;
  $this->password = $password;
  $this->db = $db;
  $this->connect();
 }

 private function connect()
 {
  $this->link = mysql_connect($this->server, $this->username, $this->password);
  mysql_select_db($this->db, $this->link);
 }

 public function __sleep()
 {
  return array('server', 'username', 'password', 'db');
 }

 public function __wakeup()
 {
  $this->connect();
 }
}
?>

__toString()

对象当成字符串时的回应方法。例如使用echo $obj;来输出一个对象

<?php
// Declare a simple class
class TestClass
{
 public function __toString() {
  return 'this is a object';
 }
}

$class = new TestClass();
echo $class;
?>

这个方法只能返回字符串,而且不可以在这个方法中抛出异常,否则会出现致命错误。

__invoke()

调用函数的方式调用一个对象时的回应方法。如下

<?php
class CallableClass 
{
 function __invoke() {
  echo 'this is a object';
 }
}
$obj = new CallableClass;
var_dump(is_callable($obj));
?>

__set_state()

调用var_export()导出类时,此静态方法会被调用。

<?php
class A
{
 public $var1;
 public $var2;

 public static function __set_state ($an_array) {
  $obj = new A;
  $obj->var1 = $an_array['var1'];
  $obj->var2 = $an_array['var2'];
  return $obj;
 }
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
var_dump(var_export($a));
?>

__clone()

当对象复制完成时调用。例如在设计模式详解及PHP实现:单例模式一文中提到的单例模式实现方式,利用这个函数来防止对象被克隆。

<?php 
public class Singleton {
 private static $_instance = NULL;

 // 私有构造方法 
 private function __construct() {}

 public static function getInstance() {
  if (is_null(self::$_instance)) {
   self::$_instance = new Singleton();
  }
  return self::$_instance;
 }

 // 防止克隆实例
 public function __clone(){
  die('Clone is not allowed.' . E_USER_ERROR);
 }
}
?>

魔术常量(Magic constants)

PHP中的常量大部分都是不变的,但是有8个常量会随着他们所在代码位置的变化而变化,这8个常量被称为魔术常量。

  • __LINE__,文件中的当前行号
  • __FILE__,文件的完整路径和文件名
  • __DIR__,文件所在的目录
  • __FUNCTION__,函数名称
  • __CLASS__,类的名称
  • __TRAIT__,Trait的名字
  • __METHOD__,类的方法名
  • __NAMESPACE__,当前命名空间的名称

这些魔术常量常常被用于获得当前环境信息或者记录日志。

以上就是本文的全部内容,希望对大家的学习有所帮助。

PHP 相关文章推荐
php遍历目录viewDir函数
Dec 15 PHP
PHP 防恶意刷新实现代码
May 16 PHP
php打开文件fopen函数的使用说明
Jul 05 PHP
详解PHP数组赋值方法
Nov 07 PHP
php判断邮箱地址是否存在的方法
Feb 13 PHP
php结合ajax实现手机发红包的案例
Oct 13 PHP
laravel如何开启跨域功能示例详解
Aug 31 PHP
tp5(thinkPHP5)操作mongoDB数据库的方法
Jan 20 PHP
php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
Sep 28 PHP
php7性能提升的原因详解
Oct 13 PHP
laravel 实现用户登录注销并限制功能
Oct 24 PHP
Git命令之分支详解
Mar 02 PHP
PHP浮点比较大小的方法
Feb 14 #PHP
PHP魔术方法使用方法汇总
Feb 14 #PHP
PHP函数超时处理方法
Feb 14 #PHP
PHP使用file_get_content设置头信息的方法
Feb 14 #PHP
PHP下使用mysqli的函数连接mysql出现warning: mysqli::real_connect(): (hy000/1040): ...
Feb 14 #PHP
PHP缓冲区用法总结
Feb 14 #PHP
PHP二维数组排序简单实现方法
Feb 14 #PHP
You might like
用PHP和Shell写Hadoop的MapReduce程序
2014/04/15 PHP
php结合ajax实现赞、顶、踩功能实例
2014/05/12 PHP
smarty模板引擎从php中获取数据的方法
2015/01/22 PHP
PHP替换Word中变量并导出PDF图片的实现方法
2020/11/26 PHP
JavaScript Accessor实现说明
2010/12/06 Javascript
JQuery防止退格键网页后退的实现代码
2012/03/23 Javascript
getComputedStyle与currentStyle获取样式(style/class)
2013/03/19 Javascript
jQuery实现类似淘宝购物车全选状态示例
2013/06/26 Javascript
jquery的父子兄弟节点查找示例代码
2014/03/03 Javascript
javascript使用prototype完成单继承
2014/12/24 Javascript
javascript动态设置样式style实例分析
2015/05/13 Javascript
浅谈js中的延迟执行和定时执行
2016/05/31 Javascript
angularjs 源码解析之scope
2016/08/22 Javascript
详解AngularJS脏检查机制及$timeout的妙用
2017/06/19 Javascript
jQuery实现表单动态加减、ajax表单提交功能
2018/06/08 jQuery
详解使用Next.js构建服务端渲染应用
2018/07/10 Javascript
Vue项目全局配置页面缓存之按需读取缓存的实现详解
2018/08/01 Javascript
JavaScript实现多态和继承的封装操作示例
2018/08/20 Javascript
引入外部js脚本加载慢与页面白屏问题的解决
2018/12/10 Javascript
详解JavaScript 中的批处理和缓存
2020/11/19 Javascript
Python中实现常量(Const)功能
2015/01/28 Python
Python中的各种装饰器详解
2015/04/11 Python
使用pyecharts无法import Bar的解决方案
2020/04/23 Python
Python实现的概率分布运算操作示例
2017/08/14 Python
在python带权重的列表中随机取值的方法
2019/01/23 Python
基于TensorFlow中自定义梯度的2种方式
2020/02/04 Python
Scrapy模拟登录赶集网的实现代码
2020/07/07 Python
html5模拟平抛运动(模拟小球平抛运动过程)
2013/07/25 HTML / CSS
经典优秀个人求职信分享
2013/12/12 职场文书
自我评价200字分享
2013/12/17 职场文书
学校评语大全
2014/05/06 职场文书
小学优秀教育工作者事迹材料
2014/05/09 职场文书
2014年医院后勤工作总结
2014/12/06 职场文书
在 SQL 语句中处理 NULL 值的方法
2021/06/07 SQL Server
Python 详解通过Scrapy框架实现爬取百度新冠疫情数据流程
2021/11/11 Python
Web应用开发TypeScript使用详解
2022/05/25 Javascript