PHP面向对象程序设计重载(overloading)操作详解


Posted in PHP onJune 13, 2019

本文实例讲述了PHP面向对象程序设计重载(overloading)操作。分享给大家供大家参考,具体如下:

重载

PHP中的”重载”与其它绝大多数面向对象语言不同,只是他们都是用的相同的名词而已。传统的”重载”是用于提供多个同名的 类方法,但各方法的参数类型和个数不同。 PHP所提供的”重载”(overloading)是指动态地”创建”类属性和方法。当调用当前环境下未定义不可见的类属性或方法时,重载方法会被调用。是通过魔术方法(magic methods)来实现的。

一般来说,把类中的成员属性都定义为private的,这更符合现实的逻辑,能够更好的对类中成员起到保护作用。但是,对成员属性的读取和赋值操作是非常频繁的,而如果在类中为每个私有属性都定义可以在对象的外部获取和赋值的公有方法,又是非常非常烦恼的。因此在PHP5.1.0以后的版本中,预定义了两个方法“__get()”和“__set()”,用来完成对所用私有属性都能获取和赋值操作,以及用来检查私有属性是否存在的方法“__isset()”和用来删除对象中私有属性方法“__unset()”。
通俗一点来说,重载在php中的含义是指,当一个对象或类使用其未定义或不可见的属性和方法时,其中的一些“处理机制”。

属性重载

对一个对象不存在的属性进行使用时,这个类中预先设定好的应对办法(处理机制)。

属性,本质就是变量,其只有4个操作:

取值:

当对一个对象不存在(未定义或不可见)的属性进行“取值”时,就会自动调用方法:__GET()方法不区分大小写。

赋值:

当对一个对象不存在(未定义或不可见)的属性进行“赋值”时,就会自动调用方法:__SET()

判断(isset):

当对一个对象不存在(未定义或不可见)的属性进行isset()判断时,就会自动调用方法:isset()

销毁(unset):

当对一个对象不存在的(未定义或不可见)属性进行unset()判断时,就会自动调用方法:unset()

以上4个方法,被称为魔术方法。

魔术方法

__GET($属性名):

在对一个对象不存在的属性进行“取值”的时候,会自动调用的方法,其中该方法可以带一个形参,表示要对之取值而又不存在的属性名(字符串),可以使用该方法对意外情况进行某种特殊的处理。

例如:

<?php
class A{
  public $p1 = 1;
}
$a1 = new A();
echo $a1->p1; //1
echo $a1->p2; //未定义$p2,会报错, Notice: Undefined property: A::$p2
?>

php的重载,使用__get()方法对上面的出错作“优雅处理”。

<?php
class A{
  public $p1 = 1;
  //private $p2 = 1; //这里将属性私有化,其实和未定义一样,对外部来说都相当于不存在
  function __get($prop_name){
    /*
    //比如可以这样处理
    echo "<br />{$prop_name}属性还未定义(不存在)!";
    return ""; //也可以返回0,或false等
    */
    //还可以这样处理
    trigger_error("发生错误:属性不存在!", E_USER_ERROR);
    die();
  }
}
$a1 = new A();
echo $a1->p1; //1
echo $a1->p2; //未定义$p2,但经过"处理"
?>

这里举一个对所用私有属性获取的操作的例子。

例子:

<?php
class Person{
  public $name;
  public $sex;
  private $age; //年龄私有化,类外不能直接访问这个属性
  function __construct($name='', $sex='', $age){
    $this->name = $name;
    $this->sex = $sex;
    $this->age = $age;
  }
  private function __get($propertyName){ //这里要用private修饰,防止类外部调用
    if($propertyName == 'age'){
      return $this->age;
    }
  }
}
$p = new Person('yeoman', '男',23);
$v1 = $p->name;
$v2 = $p->sex;
$v3 = $p->age;  //自动调用了__get()方法获取私有属性age(函数定义里面返回)
echo "name=$v1, sex=$v2, age=$v3";
?>

运行结果为:

name=yeoman, sex=男, age=23

__SET($属性名, 值):

当对一个对象不存在的属性进行“赋值”时,就会自动调用这个内部的魔术方法;其有2个形参,分别代表要对不存在的属性进行赋值的“属性名”和“属性值”。
这个方法,结合_GET方法,往往可以使我们定义的类,有一种可扩展的特性。即:类或对象的属性,可以更为方便自由。

例子:

<?php
class A{
  //定义一个属性,
  protected $prop_list = array();  //初始为空数组
  //这个方法会在A的对象使用一个不存在的属性进行赋值时调用
  function __set($p,$v){
    //echo "使用不存在的属性!";
    $this->prop_list[$p] = $v;
  }
  function __get($p){
    return $this->prop_list[$p];
  }
}
$a1 = new A();
$a1->p1 = 1;  //不存在的属性名赋值,此时会调用_set(),并传过去"p1"和1
$a1->p2 = 2;
$a1->ac = 'avc';
echo "<br />输出这些“不存在的属性”的值:";
echo "<br />a1->p1:" . $a1->p1;  //不存在的属性名取值,此时会调用_get(),并传过去"p1"
echo "<br />a1->p2:" . $a1->p2;
echo "<br />a1->ac:" . $a1->ac;
?>

运行结果为:

输出这些“不存在的属性”的值:
a1->p1:1
a1->p2:2
a1->ac:avc

__ISSET($属性名):

当对一个对象不存在的属性进行isset()判断时,就会自动调用内部方法:isset();

用法:

$v1 = isset($对象->不存在的属性);  //此时会调用这个对象所属类中的魔术方法:isset()

例子:

<?php
class A{
  //定义一个属性,
  protected $prop_list = array();  //初始为空数组
  //这个方法会在A的对象使用一个不存在的属性进行赋值时调用
  function __set($p,$v){
    //echo "使用不存在的属性!";
    $this->prop_list[$p] = $v;
  }
  function __get($p){
    if($this->prop_list[$p]){
      return $this->prop_list[$p];
    }else{
      return "该属性不存在!";
    }
  }
  function __isset($prop){  //__isset()是自定义的方法, isset()是系统函数
    $re = isset($this->prop_list[$prop]);
    return $re;
  }
}
$a1 = new A();
$a1->p1 = 1;//不存在的属性名赋值,此时会调用_set(),并传过去"p1"和1
$a1->p2 = 2;
$a1->ac = 'avc';
echo "<br />输出这些“不存在的属性”的值";
echo "<br />a1->p1:" . $a1->p1;//不存在的属性名取值,此时会调用_get(),并传过去"p1"
echo "<br />a1->p2:" . $a1->p2;
echo "<br />a1->ac:" . $a1->ac;
//下面演示isset判断不存在的属性
$v1 = isset($a1->p1); //存在
$v2 = isset($a1->ppp1);  //不存在
var_dump($v1);
echo "<br />";
var_dump($v2);
?>

运行结果:

输出这些“不存在的属性”的值
a1->p1:1
a1->p2:2
a1->ac:avc
boolean true
boolean false

__UNSET($属性名)

当对一个对象不存在的属性进行unset()销毁时,就会自动调用内部方法:unset();

<?php
class A{
  //定义一个属性,
  protected $prop_list = array();  //初始为空数组
  //这个方法会在A的对象使用一个不存在的属性进行赋值时调用
  function __set($p,$v){
    //echo "使用不存在的属性!";
    $this->prop_list[$p] = $v;
  }
  function __get($p){
    if($this->prop_list[$p]){
      return $this->prop_list[$p];
    }else{
      return "该属性不存在!";
    }
  }
  function __unset($prop){
    unset($this->prop_list[$prop]);
  }
}
$a1 = new A();
$a1->p1 = 1;//不存在的属性名赋值,此时会调用_set(),并传过去"p1"和1
echo "<br />a1->p1:" . $a1->p1;//不存在的属性名取值,此时会调用_get(),并传过去"p1"
//下面演示unset销毁一个不存在的属性
unset($a1->p1);
echo "<br />a1->p1:" . $a1->p1;
?>

运行结果为:

a1->p1:1
a1->p1:该属性不存在!

下面的例子中,声明一个Person类,并将所有的成员属性设置成private的。在类中添加自定义的“__isset()”和“__unset()”两个方法。在类外部使用“isset()”和“unset()”函数时,会自动调用这两个方法。代码如下:

<?php
class Person{
  private $name; //此属性被封住
  private $sex;
  private $age;
  function __construct($name='', $sex='男', $age){
    $this->name = $name;
    $this->sex = $sex;
    $this->age = $age;
  }
  private function __isset($propertyName){  //需要一个参数,是测定的私有属性的名称
    if($propertyName == 'name'){
      return false;  //返回假,不允许在类外部测定name属性
    }
    return isset($this->$propertyName);  //这里propertyName要加$符,因为这是参数,不是属性
  }
  private function __unset($propertyName){
    if($propertyName == 'name')
      return; //退出方法,不允许删除对象中的name属性
    unset($this->$propertyName); //这里propertyName要加$符
  }
  public function say(){
    echo "名字:" . $this->name . ",性别:" . $this->sex . ",年龄:" . $this->age . "<br />";
  }
}
$person = new Person("yeoman", "男", 23);
var_dump(isset($person->name));  //输出bool(false),不允许测定name属性
var_dump(isset($person->sex)); //输出bool(true),存在sex私有属性
var_dump(isset($person->age)); //输出bool(true),存在age私有属性
var_dump(isset($person->id)); //输出bool(false),测定对象中不存在id属性
unset($person->name); //删除私有属性name,但在 __unset()中不允许删除
unset($person->sex);  //删除对象中的私有属性sex,删除成功
unset($person->age);
$person->say();  //对象中的sex和age属性被删除,输出:名字:yeoman,性别:,年龄:
?>

运行结果:

boolean false
boolean true
boolean true
boolean false
名字:yeoman,性别:,年龄:

方法重载

当对一个对象不存在的实例方法进行“调用”时,会自动调用类中的__call()这个魔术方法;

当对一个类不存在的静态方法进行“调用”时,会自动调用类中的__callstatic()这个魔术方法。

例子:直接调用不存在的方法

<?php
ini_set('display_errors',1);
class A{
}
$a = new A();
$a->f1(); //不存在的方法
?>

会报错,报错内容为:

Fatal error: Uncaught Error: Call to undefined method A::f1()

对上面报错作“优雅处理”:

<?php
class A{
  //当对这个类的对象不存在的实力方法进行调用时,会自动调用本方法
  //这个方法必须带2个形参:
  //$methodName:表示要调用的不存在的方法名;
  //$argument:表示要调用该不存在的方法时,所使用的实参数据,是一个数组。
  function __call($methodName, $argument){
    //echo "__call被调用了!";
    echo $methodName . "()方法不存在!";
  }
}
$a = new A();
$a->f1(); //不存在的方法,但经过处理
?>

运行结果为:

f1()方法不存在!

当对一个类不存在的静态方法进行“调用”时,会自动调用类中的__callstatic()这个魔术方法。和上面的处理类似。

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
php中Smarty模板初体验
Aug 08 PHP
PHP spl_autoload_register实现自动加载研究
Dec 06 PHP
PHP中copy on write写时复制机制介绍
May 13 PHP
php+mysql大量用户登录解决方案分析
Dec 29 PHP
讲解WordPress中用于获取评论模板和搜索表单的PHP函数
Dec 28 PHP
PHP使用Memcache时模拟命名空间及缓存失效问题的解决
Feb 27 PHP
PHP函数shuffle()取数组若干个随机元素的方法分析
Apr 02 PHP
thinkphp框架实现数据添加和显示功能
Jun 29 PHP
php curl上传、下载、https登陆实现代码
Jul 23 PHP
php表单处理操作
Nov 16 PHP
PHP的mysqli_stat()函数讲解
Jan 23 PHP
tp5.1 框架数据库高级查询技巧实例总结
May 25 PHP
PHP面向对象程序设计之构造方法和析构方法详解
Jun 13 #PHP
PHP Cli 模式设置进程名称的方法
Jun 12 #PHP
PHP面向对象程序设计之对象克隆clone和魔术方法__clone()用法分析
Jun 12 #PHP
PHP面向对象程序设计之对象的遍历操作示例
Jun 12 #PHP
PHP面向对象程序设计内置标准类,普通数据类型转为对象类型示例
Jun 12 #PHP
PHP下用Swoole实现Actor并发模型的方法
Jun 12 #PHP
PHP面向对象类型约束用法分析
Jun 12 #PHP
You might like
php中显示数组与对象的实现代码
2011/04/18 PHP
php操作XML、读取数据和写入数据的实现代码
2014/08/15 PHP
Symfony2在Nginx下的配置方法图文教程
2016/02/04 PHP
PHP编写daemon process详解及实例代码
2016/09/30 PHP
Yii2实现UploadedFile上传文件示例
2017/02/15 PHP
golang、python、php、c++、c、java、Nodejs性能对比
2017/03/12 NodeJs
[原创]php正则删除html代码中class样式属性的方法
2017/05/24 PHP
纯JavaScript实现的完美渐变弹出层效果代码
2010/04/02 Javascript
基于jquery1.4.2的仿flash超炫焦点图播放效果
2010/04/20 Javascript
运算符&amp;&amp;的三个不同层次
2013/04/07 Javascript
Jquery遍历节点的方法小集
2014/01/22 Javascript
javascript实现youku的视频代码自适应宽度
2015/05/25 Javascript
整理Javascript基础语法学习笔记
2015/11/29 Javascript
angularjs表格ng-table使用备忘录
2016/03/09 Javascript
JS跨域交互(jQuery+php)之jsonp使用心得
2016/07/01 Javascript
Node.js 日志处理模块log4js
2016/08/28 Javascript
JS实现列表的响应式排版(推荐)
2016/09/01 Javascript
jQuery+正则+文本框只能输入数字的实现方法
2016/10/07 Javascript
浅谈webpack打包过程中因为图片的路径导致的问题
2018/02/21 Javascript
vue实现下拉加载其实没那么复杂
2019/08/13 Javascript
Vue移动端实现图片上传及超过1M压缩上传
2019/12/23 Javascript
python线程池的实现实例
2013/11/18 Python
python学习之面向对象【入门初级篇】
2017/01/21 Python
详解如何管理多个Python版本和虚拟环境
2019/05/10 Python
python小程序基于Jupyter实现天气查询的方法
2020/03/27 Python
Keras在训练期间可视化训练误差和测试误差实例
2020/06/16 Python
input元素的url类型和email类型简介
2012/07/11 HTML / CSS
澳大利亚领先的时尚内衣零售商:Bras N Things
2020/07/28 全球购物
艺术爱好者的自我评价分享
2013/10/08 职场文书
关于梦想的演讲稿
2014/05/05 职场文书
弘扬雷锋精神演讲稿
2014/05/10 职场文书
过程装备与控制工程专业求职信
2014/07/02 职场文书
2014年乡镇卫生院工作总结
2014/11/24 职场文书
2014年标准化工作总结
2014/12/17 职场文书
MySQL学习总结-基础架构概述
2021/04/05 MySQL
IDEA2021.2配置docker如何将springboot项目打成镜像一键发布部署
2021/09/25 Java/Android