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 相关文章推荐
Windows下PHP的任意文件执行漏洞
Oct 09 PHP
php生成缩略图的类代码
Oct 02 PHP
php 抽象类的简单应用
Sep 06 PHP
关于php正则匹配汉字的方法介绍
Apr 25 PHP
5种PHP创建数组的实例代码分享
Jan 17 PHP
PHP与MYSQL中UTF8 中文排序示例代码
Oct 23 PHP
学习php开源项目的源码指南
Dec 21 PHP
PHP实现的简单缓存类
Jul 29 PHP
百度地图API使用方法详解
Aug 25 PHP
解决微信授权回调页面域名只能设置一个的问题
Dec 11 PHP
php使用curl获取header检测开启GZip压缩的方法
Aug 15 PHP
浅谈PHPANALYSIS提取关键字
Mar 08 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 allow_url_include的应用和解释
2010/04/22 PHP
关于php循环跳出的问题
2013/07/01 PHP
PHP 面向对象程序设计(oop)学习笔记 (五) - PHP 命名空间
2014/06/12 PHP
什么是OneThink oneThink后台添加插件步骤
2016/04/13 PHP
自制PHP框架之模型与数据库
2017/05/07 PHP
PHP实现重载的常用方法实例详解
2017/10/18 PHP
在Laravel中使用GuzzleHttp调用第三方服务的API接口代码
2019/10/15 PHP
jQuery 使用手册(一)
2009/09/23 Javascript
在JavaScript中使用timer示例
2014/05/08 Javascript
基于jquery的文字向上跑动类似跑马灯的效果
2014/09/22 Javascript
AngularJS基础 ng-copy 指令实例代码
2016/08/01 Javascript
使用smartupload组件实现jsp+jdbc上传下载文件实例解析
2017/01/05 Javascript
js实现移动端编辑添加地址【模仿京东】
2017/04/28 Javascript
自制简易打赏功能的实例
2017/09/02 Javascript
深入理解JavaScript的值传递和引用传递
2018/10/24 Javascript
Vue.js的复用组件开发流程完整记录
2018/11/29 Javascript
灵活使用console让js调试更简单的方法步骤
2019/04/23 Javascript
Vue结合路由配置递归实现菜单栏功能
2020/06/16 Javascript
vuex的使用和简易实现
2021/01/07 Vue.js
Ubuntu 16.04 LTS中源码安装Python 3.6.0的方法教程
2016/12/27 Python
python模拟菜刀反弹shell绕过限制【推荐】
2019/06/25 Python
python中bs4.BeautifulSoup的基本用法
2019/07/27 Python
纯CSS3实现绘制各种图形实现代码详细整理
2012/12/26 HTML / CSS
Css3圆角边框制作代码
2015/11/18 HTML / CSS
amazeui模态框弹出后立马消失并刷新页面
2020/08/19 HTML / CSS
维氏瑞士军刀英国网站:Victorinox英国
2019/07/04 全球购物
几道Web/Ajax的面试题
2016/11/05 面试题
老公给老婆的道歉信
2014/01/10 职场文书
校园奶茶店创业计划书
2014/01/23 职场文书
市场督导岗位职责
2015/04/10 职场文书
买卖合同纠纷代理词
2015/05/25 职场文书
护士岗前培训心得体会
2016/01/08 职场文书
银行文明优质服务培训心得体会
2016/01/09 职场文书
2016教师廉洁教育心得体会
2016/01/13 职场文书
五年级作文之成长
2019/09/16 职场文书
Nginx解决403 forbidden的完整步骤
2021/04/01 Servers