详解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 相关文章推荐
JAVA/JSP学习系列之七
Oct 09 PHP
PHP+XML 制作简单的留言本 图文教程
Nov 02 PHP
php中的观察者模式
Mar 24 PHP
PHP中的float类型使用说明
Jul 27 PHP
PHP表单验证的3个函数ISSET()、empty()、is_numeric()的使用方法
Aug 22 PHP
百度地图API应用之获取用户的具体位置
Jun 10 PHP
详解WordPress中简码格式标签编写的基本方法
Dec 22 PHP
PHP实现适用于文件内容操作的分页类
Jun 15 PHP
PHP实现JS中escape与unescape的方法
Jul 11 PHP
PHP在线打包下载功能示例
Oct 15 PHP
基于PHP的加载类操作以及其他两种魔术方法的应用实例
Aug 28 PHP
使用laravel和ajax实现整个页面无刷新的操作方法
Oct 03 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 xml-rpc远程调用
2008/12/19 PHP
PHP设计模式之装饰者模式
2012/02/29 PHP
CI框架入门之MVC简单示例
2016/11/21 PHP
IE和firefox浏览器的event事件兼容性汇总
2009/12/06 Javascript
得到jQuery detach()后节点中的某个值实现代码
2013/02/05 Javascript
jQuery对html元素取值与赋值的方法
2013/11/20 Javascript
Javascript基础教程之数据类型转换
2015/01/18 Javascript
chrome浏览器当表单自动填充时如何去除浏览器自动添加的默认样式
2015/10/09 Javascript
gulp安装以及打包合并的方法教程
2017/11/19 Javascript
详解Nuxt.js Vue服务端渲染摸索
2018/02/08 Javascript
浅谈mvvm-simple双向绑定简单实现
2018/04/18 Javascript
JS实现json对象数组按对象属性排序操作示例
2018/05/18 Javascript
vue.js引入外部CSS样式和外部JS文件的方法
2019/01/06 Javascript
JavaScript函数式编程(Functional Programming)纯函数用法分析
2019/05/22 Javascript
JavaScript oncopy事件用法实例解析
2020/05/13 Javascript
ES6扩展运算符和rest运算符用法实例分析
2020/05/23 Javascript
[02:20]DOTA2中文配音宣传片
2013/05/22 DOTA
[01:00:04]DOTA2上海特级锦标赛B组小组赛#1 Alliance VS Spirit第二局
2016/02/26 DOTA
python 将字符串完成特定的向右移动方法
2019/06/11 Python
Django MEDIA的配置及用法详解
2019/07/25 Python
pytorch 利用lstm做mnist手写数字识别分类的实例
2020/01/10 Python
使用Python3 poplib模块删除服务器多天前的邮件实现代码
2020/04/24 Python
Django 如何使用日期时间选择器规范用户的时间输入示例代码详解
2020/05/22 Python
美国最便宜的旅游网站:CheapTickets
2017/07/09 全球购物
医生进修自我鉴定
2014/01/19 职场文书
高中学生干部学习的自我评价
2014/02/21 职场文书
班级学习计划书
2014/04/27 职场文书
地下停车场租赁协议范本
2014/10/07 职场文书
习近平在党的群众路线教育实践活动总结大会上的讲话
2014/10/21 职场文书
企业爱心捐款倡议书
2015/04/27 职场文书
2015年度信用社工作总结
2015/05/04 职场文书
公司员工手册范本
2015/05/14 职场文书
转变工作作风心得体会
2016/01/23 职场文书
react antd实现动态增减表单
2021/06/03 Javascript
详解Java七大阻塞队列之SynchronousQueue
2021/09/04 Java/Android
在Python 中将类对象序列化为JSON
2022/04/06 Python