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 相关文章推荐
cmd下运行php脚本
Nov 25 PHP
PHP错误抑制符(@)导致引用传参失败Bug的分析
May 02 PHP
php开发过程中关于继承的使用方法分享
Jun 17 PHP
zf框架的session会话周期及次数限制使用示例
Mar 13 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(七)
Jun 23 PHP
PHP实现的一致性哈希算法完整实例
Nov 14 PHP
Yii2.0 Basic代码中路由链接被转义的处理方法
Sep 21 PHP
PHP基于反射机制实现插件的可插拔设计详解
Nov 10 PHP
老生常谈文本文件和二进制文件的区别
Feb 27 PHP
Django中的cookie与session操作实例代码
Aug 17 PHP
PHP rmdir()函数的用法总结
Jul 02 PHP
阿里对象存储OSS在laravel框架中的使用方法
Oct 13 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模板,主要想体现一下思路
2006/12/25 PHP
ie6 动态缩略图不显示的原因
2009/06/21 PHP
PHP简单实现DES加密解密的方法
2016/07/12 PHP
javascript attachEvent和addEventListener使用方法
2009/03/19 Javascript
使用JavaScript 实现对象 匀速/变速运动的方法
2013/05/08 Javascript
Google Dart编程语法和基本类型学习教程
2013/11/27 Javascript
一个简单不报错的summernote 图片上传案例
2016/07/11 Javascript
基于jQuery的AJAX和JSON实现纯html数据模板
2016/08/09 Javascript
jQuery实现带延时功能的水平多级菜单效果【附demo源码下载】
2016/09/21 Javascript
自制微信公众号一键排版工具
2016/09/22 Javascript
详解AngularJS 路由 resolve用法
2017/04/24 Javascript
详解react-native-fs插件的使用以及遇到的坑
2017/09/12 Javascript
如何选择适合你的JavaScript框架
2017/11/20 Javascript
利用jQuery+localStorage实现一个简易的计时器示例代码
2017/12/25 jQuery
nodejs实现套接字服务功能详解
2018/06/21 NodeJs
Nodejs实现爬虫抓取数据实例解析
2018/07/05 NodeJs
vue2.0中set添加属性后视图不能更新的解决办法
2019/02/22 Javascript
微信小程序iOS下拉白屏晃动问题解决方案
2019/10/12 Javascript
vue全屏事件开发详解
2020/06/17 Javascript
Python迭代器和生成器介绍
2015/03/06 Python
python读取dicom图像示例(SimpleITK和dicom包实现)
2020/01/16 Python
Python中logging日志记录到文件及自动分割的操作代码
2020/08/05 Python
Python通过format函数格式化显示值
2020/10/17 Python
python爬取招聘要求等信息实例
2020/11/20 Python
Python使用Opencv实现边缘检测以及轮廓检测的实现
2020/12/31 Python
标记环介质访问控制协议
2016/03/27 面试题
Java面试题:请说出如下代码的输出结果
2013/04/22 面试题
地球一小时倡议书
2014/04/15 职场文书
幼儿园课题实施方案
2014/05/14 职场文书
党的群众路线查摆剖析材料
2014/10/10 职场文书
2014年检验员工作总结
2014/11/19 职场文书
原告离婚代理词
2015/05/23 职场文书
2015年幼儿教育工作总结
2015/07/24 职场文书
2016年校园社会综合治理宣传月活动总结
2016/03/16 职场文书
Python 快速验证代理IP是否有效的方法实现
2021/07/15 Python
讲解Python实例练习逆序输出字符串
2022/05/06 Python