详解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程序的国际化实现方法(利用gettext)
Aug 14 PHP
php selectradio和checkbox默认选择的实现方法详解
Jun 29 PHP
解决php接收shell返回的结果中文乱码问题
Jan 23 PHP
PHP图片库imagemagick安装方法
Sep 23 PHP
php中文字符串截取方法实例总结
Sep 30 PHP
php获取json数据所有的节点路径
May 17 PHP
php图片水印添加、压缩、剪切的封装类实现
Apr 18 PHP
PHP中include和require的区别实例分析
May 07 PHP
Laravel使用消息队列需要注意的一些问题
Dec 13 PHP
PHP实现的数组和XML文件相互转换功能示例
Mar 15 PHP
php微信公众号开发之快递查询
Oct 20 PHP
小程序微信支付功能配置方法示例详解【基于thinkPHP】
May 05 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
一个取得文件扩展名的函数
2006/10/09 PHP
php使用pdo连接报错Connection failed SQLSTATE的解决方法
2014/12/15 PHP
[原创]php实现数组按拼音顺序排序的方法
2017/05/03 PHP
Thinkphp 3.2框架使用Redis的方法详解
2019/10/24 PHP
“不能执行已释放的Script代码”错误的原因及解决办法
2007/09/09 Javascript
jQuery1.6 使用方法一
2011/11/23 Javascript
JavaScript面向对象(极简主义法minimalist approach)
2012/07/17 Javascript
js Select下拉列表框进行多选、移除、交换内容的具体实现方法
2013/08/13 Javascript
javascript屏蔽右键代码
2014/05/15 Javascript
node.js中的fs.symlink方法使用说明
2014/12/15 Javascript
javascript实现类似超链接的效果
2014/12/26 Javascript
jQuery 1.9.1源码分析系列(十)事件系统之绑定事件
2015/11/19 Javascript
通过bootstrap全面学习less
2016/11/09 Javascript
使用jsonp实现跨域获取数据实例讲解
2016/12/25 Javascript
javascript闭包功能与用法实例分析
2017/04/06 Javascript
基于vue实现swipe轮播组件实例代码
2017/05/24 Javascript
微信小程序设置全局请求URL及封装wx.request请求操作示例
2019/04/02 Javascript
详解NodeJs项目 CentOs linux服务器线上部署
2019/09/16 NodeJs
js节流防抖应用场景,以及在vue中节流防抖的具体实现操作
2020/09/21 Javascript
[02:41]辉夜杯现场一家三口 “我爸玩风行 我玩血魔”
2015/12/27 DOTA
利用Python找出序列中出现最多的元素示例代码
2017/12/08 Python
windows7 32、64位下python爬虫框架scrapy环境的搭建方法
2018/11/29 Python
对Python使用mfcc的两种方式详解
2019/01/09 Python
对PyQt5中树结构的实现方法详解
2019/06/17 Python
美国最灵活的移动提供商:Tello
2017/07/18 全球购物
阿根廷票务网站:StubHub阿根廷
2018/04/13 全球购物
经典c++面试题二
2015/08/14 面试题
AJAX应用和传统Web应用有什么不同
2013/08/24 面试题
计算机专业自荐信
2014/05/24 职场文书
英语三分钟演讲稿
2014/08/19 职场文书
迎新生欢迎词
2015/01/23 职场文书
运动会三级跳加油稿
2015/07/21 职场文书
青年联谊会致辞
2015/07/31 职场文书
导游词之西安大清真寺
2019/12/17 职场文书
本地通过nginx配置反向代理的全过程记录
2021/03/31 Servers
golang判断key是否在map中的代码
2021/04/24 Golang