详解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编写的导航条程序
Oct 09 PHP
PHP安全配置详细说明
Sep 26 PHP
php排序算法(冒泡排序,快速排序)
Oct 09 PHP
PHP去掉从word直接粘贴过来的没有用格式的函数
Oct 29 PHP
Laravel中注册Facades的步骤详解
Mar 16 PHP
Zend Framework教程之连接数据库并执行增删查的方法(附demo源码下载)
Mar 21 PHP
老生常谈PHP 文件写入和读取(必看篇)
May 22 PHP
PHP判断json格式是否正确的实现代码
Sep 20 PHP
PHP 二维array转换json的实例讲解
Aug 21 PHP
PHP使用redis位图bitMap 实现签到功能
Oct 08 PHP
PHP使用PDO实现mysql防注入功能详解
Dec 20 PHP
PHP时间相关常用函数用法示例
Jun 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作的文本留言本的例子(五)
2006/10/09 PHP
解析PHP提交后跳转
2013/06/23 PHP
thinkphp3.2.2前后台公用类架构问题分析
2014/11/25 PHP
yii插入数据库防并发的简单代码
2017/05/27 PHP
PHP弱类型语言中类型判断操作实例详解
2017/08/10 PHP
PHP实现获取文件mime类型多种方法解析
2020/05/28 PHP
搭建pomelo 开发环境
2014/06/24 Javascript
详解JavaScript的策略模式编程
2015/06/24 Javascript
JS实现可直接显示网页代码运行效果的HTML代码预览功能实例
2015/08/06 Javascript
JavaScript代码实现图片循环滚动效果
2020/03/19 Javascript
原生JS封装ajax 传json,str,excel文件上传提交表单(推荐)
2016/06/21 Javascript
jQuery progressbar通过Ajax请求实现后台进度实时功能
2016/10/11 Javascript
js判断手机号是否正确并返回的实现代码
2017/01/17 Javascript
微信小程序实现全国机场索引列表
2018/01/31 Javascript
Angular使用操作事件指令ng-click传多个参数示例
2018/03/27 Javascript
Vue编写可显示周和月模式的日历 Vue自定义日历内容的显示
2019/06/26 Javascript
JS实现数据动态渲染的竖向步骤条
2020/06/24 Javascript
微信小程序上传帖子的实例代码(含有文字图片的微信验证)
2020/07/11 Javascript
[00:44]TI7不朽珍藏III——军团指挥官不朽展示
2017/07/15 DOTA
Python使用urllib2获取网络资源实例讲解
2013/12/02 Python
Python验证码识别处理实例
2015/12/28 Python
python编程实现归并排序
2017/04/14 Python
python连接数据库的方法
2017/10/19 Python
VTK与Python实现机械臂三维模型可视化详解
2017/12/13 Python
Windows下的Python 3.6.1的下载与安装图文详解(适合32位和64位)
2018/02/21 Python
解决Python 爬虫URL中存在中文或特殊符号无法请求的问题
2018/05/11 Python
谈谈Python中的while循环语句
2019/03/10 Python
Python单元和文档测试实例详解
2019/04/11 Python
python scipy卷积运算的实现方法
2019/09/16 Python
基于python实现获取网页图片过程解析
2020/05/11 Python
内业资料员岗位职责
2014/01/04 职场文书
2014年寒假社会实践活动心得体会
2014/04/07 职场文书
工厂门卫的岗位职责
2014/07/27 职场文书
干部对照检查材料范文
2014/08/26 职场文书
工作失职检讨书
2015/01/26 职场文书
2016年少先队活动总结
2016/04/06 职场文书