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安装为Apache DSO
Oct 09 PHP
Excel数据导入Mysql数据库的实现代码
Jun 05 PHP
php 批量生成html,txt文件的实现代码
Jun 26 PHP
深入解析php中的foreach函数
Aug 31 PHP
PHP 面向对象程序设计(oop)学习笔记 (五) - PHP 命名空间
Jun 12 PHP
PHP将回调函数作用到给定数组单元的方法
Aug 19 PHP
php中current、next与reset函数用法实例
Nov 17 PHP
php将字符串转换成16进制的方法
Mar 17 PHP
PHP代码判断设备是手机还是平板电脑(两种方法)
Oct 19 PHP
CI操作cookie的方法分析(基于helper类库)
Mar 28 PHP
PHP7新增运算符用法实例分析
Sep 26 PHP
PHP查询大量数据内存耗尽问题的解决方法
Oct 28 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
使用淘宝IP库获取用户ip地理位置
2013/10/27 PHP
php 使用GD库为页面增加水印示例代码
2014/03/24 PHP
PHP中is_file()函数使用指南
2015/05/08 PHP
javascript 图片上一张下一张链接效果代码
2010/03/12 Javascript
JS判断页面加载状态以及添加遮罩和缓冲动画的代码
2012/10/11 Javascript
Extjs grid panel自带滚动条失效的解决方法
2014/09/11 Javascript
基于jQuery实现美观且实用的倒计时实例代码
2015/12/30 Javascript
防止Node.js中错误导致进程阻塞的办法
2016/08/11 Javascript
基于JavaScript实现鼠标向下滑动加载div的代码
2016/08/31 Javascript
AngularJS 表达式详解及实例代码
2016/09/14 Javascript
jQuery 特性操作详解及实例代码
2016/09/29 Javascript
微信小程序开发的四十个技术窍门总结(推荐)
2017/01/23 Javascript
Angular使用$http.jsonp发送跨站请求的方法
2017/03/16 Javascript
jsonp跨域获取数据的基础教程
2018/07/01 Javascript
JS实现随机抽选获奖者
2019/11/07 Javascript
[01:00:14]2018DOTA2亚洲邀请赛 4.6 淘汰赛 VP vs TNC 第三场
2018/04/10 DOTA
Django中URL视图函数的一些高级概念介绍
2015/07/20 Python
shelve  用来持久化任意的Python对象实例代码
2016/10/12 Python
基于Python和Scikit-Learn的机器学习探索
2017/10/16 Python
django 2.0更新的10条注意事项总结
2018/01/05 Python
Python列表推导式与生成器表达式用法示例
2018/02/08 Python
python使用tomorrow实现多线程的例子
2019/07/20 Python
Python代码使用 Pyftpdlib实现FTP服务器功能
2019/07/22 Python
10个Python面试常问的问题(小结)
2019/11/20 Python
TensorFlow MNIST手写数据集的实现方法
2020/02/05 Python
pytorch Dataset,DataLoader产生自定义的训练数据案例
2021/03/03 Python
Brydge英国:适用于Apple iPad和Microsoft Surface Pro的蓝牙键盘
2019/05/16 全球购物
美国时尚大码女装购物网站:Avenue
2019/05/24 全球购物
地理教师岗位职责
2014/03/16 职场文书
房屋租赁合同补充协议
2014/10/11 职场文书
西安兵马俑导游词
2015/02/02 职场文书
python实战之一步一步教你绘制小猪佩奇
2021/04/22 Python
Python趣味挑战之给幼儿园弟弟生成1000道算术题
2021/05/28 Python
php双向队列实例讲解
2021/11/17 PHP
Python采集壁纸并实现炫轮播
2022/04/30 Python
Python自动化实战之接口请求的实现
2022/05/30 Python