陈力:传智播客古代 珍宝币 泡泡龙游戏开发第34讲:PHP 封装、继承、多态

封装就是把抽象出的数据和对数据的操作封装在一起,通过public、  protected和private进行修饰。继承可以解决代码复用,“重载”是类的多态的一种实现。贵阳网站建设的朋友必须要掌握php面向对象编程的三大特征:封装、继承、多态。本节陈力:传智播客古代 珍宝币 泡泡龙游戏开发第34讲:PHP 封装、继承、多态。

一、PHP程序设计语言的抽象
    我们在前面去定义一个类时候,实际上就是把一类事物的共有的属性和行为提取出来,形成一个物理模型(模板)。这种研究问题的方法称为抽象。

class Account {
 public $blance;
 public $no;
 public function qun(){
}
public function cun(){
}
}

二、PHP程序设计语言的封装
    封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。
那么在php中如何实现这种类似的控制呢?请大家看一个小程序。不能随便查看人的年龄,工资等隐私...

class Person{
 public $name;
 private  $age;
 private  $salary;
 function __construct($name,$age,$salary){
 $this->name=$name;
 $this->age=$age;
 $this->salary=$salary
}
}
//创建一个人对象:
$p1=new Person(“宋江”,30,1500);
//查看薪水
$p1->salary;
//访问时出错,提示不能访问私有属性。
Php程序设计语言提供了三种访问控制符号:
Public:表示全局,可以在本类,类外部,子类 中使用。
Protected:表示受到保护,可以在本类、子类中使用。
Private:表示私有,只能在本类使用。

这三个控制修饰符号可以对属性和方法修饰。
如果一个方法没有访问修饰符,则默认是public;属性必须指定访问修饰符。
在类中,方法之间可以互相调用,但是需要使用 $this引用。
function test11(){
  $this->test12();
}
protected function test12(){
  echo "test12 hello";
}

举例说明:
class Person{
  public $name;
  protected  $age;
  private  $salary;
  function __construct($name,$age,$salary){
   $this->name=$name;
   $this->age=$age;
   $this->salary=$salary;
  }
  //成员方法
  function showInfo(){
   //说明在本类中可以使用 public protected和private修饰的变量。
   echo $this->name."||".$this->age."||".$this->salary;
  }
 }
 $p1=new Person("孙悟空",30,1000); //创建一个人
 echo $p1->name; //可以访问
 echo $p1->age;  //报错
 echo $p1->salary;//报错。

我们现在就想去访问protected 变量或者 private 变量,通常的做法是提供public 函数去访问这些变量。形式是
 public function setXxx($val){
}
public function getXxx(){
}

1)查看薪水 (private )
//获取这个人的薪水
public function getSalary($user,$pass){
   if($user=="admin" && $pass="123"){
    return $this->salary;
   }else{
    return "对不起,你没有权限看";
   }
}
2)修改人的年龄
提供了两个函数.
//修改年龄,对输入的值,进行校验.
public function setAge($age){
 if($age>1 && $age<120){
  $this->age=$age;
  }else {
   echo "年龄范围不对";
    }
}
//查看年龄
public function getAge(){
  return $this->age;
}

PHP为我们提供了一对方法:__set() , __get()
__set() 对protected 或是 private属性,进行赋值操作
__set($name,$value)
__get()获取protected 或者private属性的值.
__get($name)
例子:
**用一对__set和__get方法就可以处理所有的private 和 protected属性,这种方式简单但是不够灵活,比如我要求在设置age的时候,如果age不在 1-150之间,就提示错误
**__set 和 __get就显得不方法,所以我们建议大家使用自定义set和get方法,更加灵活,可读性也好.
<?php 
class Myfun{
 protected $name;
 private $age;
 function __set($pro_name,$pro_value){                  
  $this->$pro_name = $pro_value;
 }
 function __get($pro_name){
  if(isset($pro_name)){
   return $this->$pro_name;
  }else{ 
   return null;
  }
 } 
}
  $m = new Myfun();
  $m->name = "张三3";
  echo "你的名字:".$m->name;
  $m->age=89;
  echo "你的年龄是".$m->age;
  echo "<hr>";
  //自定义set 和 get方法.
  class Test{
   private $name;
  public function getName(){
   return $this->name;
  }
  public function setName($name){
  $this->name = $name;
  }
  }
  $t = new Test();
  $t->setName("lisi");
  echo $t->getName();
?>

这种形式通过一对 __set  和 __get方法来操作我们的变量,不推荐。
class A{
  private $n1;
  private $n2;
  private $n3;
  //使用__set 方法来管理所有的属性
  public function __set($pro_name,$pro_val){
   $this->pro_name=$pro_val;
  }
  //使用__get 可以获取所有的属性值
  public function  __get($pro_name){
   if(isset($pro_name)){
    return $this->pro_name;
   }else{
    return null;
   }
  }
 }
 $a1=new A();
 $a1->n1="hello";//报错
 echo $a1->n1;
 $a1->n2=890;
 echo "||".$a1->n2;

可以直接写一个方法了操作变量
class Peron{
 protected n1;
 private $n2;
 function showInfo($n1){
       $this->n1=$n1;
 echo $this->n1.”||”$this->n2;
}
}

三、PHP程序设计语言的继承
     继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类(比如刚才的Student),在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 
class 子类名 extends 父类名{ 
}
这样,子类就会自动拥有父类定义的属性和方法。
我们对extend1.php 改进,使用继承的方法,
请大家注意体会使用继承的好处.
//应用场景 开发一套学生管理系统(Pupil, Graduate , ...)
class Pupil{
  public $name;
  protected $age;
  protected $grade;
  public function showInfo(){
   echo $this->name."||".$this->age;
  }
  public function tesing(){
   echo " 小学生考试..";
  }
 }
 class Graduate{
  public $name;
  protected $age;
  protected $grade;
 public function showInfo(){
   echo $this->name."||".$this->age;
 }
 public function tesing(){
   echo "研究生考试..";
  }
}

从上面的代码我们看出,代码的复用性不高,同时也会让管理代码成本增高.
解决之道(继承);

在我们使用继承对上面的代码,进行改写.
代码:
 //应用场景 开发一套学生管理系统(Pupil, Graduate , ...)
 //父类
 class Stu{
  public $name;
  protected $age;
  protected $grade;
 public function showInfo(){
  echo $this->name;
 }
}
//子类
 class Pupil extends Stu{
  public function testing(){
   echo " 小学生考试..";
  }
}
class Graduate extends Stu{
 public function testing(){
   echo "研究生考试..";
  }
}
 //创建学生
 $stu1=new Pupil();
 $stu1->name="小明";
 $stu1->testing();
 $stu1->showInfo();
 //创建一个研究生
 $stu2=new Graduate();
 $stu2->name="老明";
 $stu2->testing();
 $stu2->showInfo();

从上面的代码我们可以看出:
所谓继承就是一个子类通过 extends  父类  把父类的 (public / protected)属性和(public / protected)方法继承下来。
继承的基本语法是:
class 类名 extends 父类名{
 //在写自己需要的属性和方法.
}

继承细节:
(1)父类的 public  、protected 的属性和方法被继承. private 的属性和方法没有被继承。
(2)一个类只能继承一个父类,(直接继承).如果你希望继承多个类的属性和方法,则使用多层继承。
class A{
  public $n1=90;
 }
 class B extends A{
  public $n2="hello";
 }

class C extends B{}
 $c=new C();
 echo $c->n1;
(3)当创建子类对象的时候,默认情况下不会自动调用父类的构造方法。
class A{
  public $n1=90;
  //构造方法
  public function __construct(){
   echo "A __construct";
  }
 }
 class B extends A{
  function __construct(){
   echo "B __construct";
  }
  }
 //创建B对象实例
 $b=new B();
(4)如果我们希望去调用父类的构造方法,或者其它的方法(public /  protected),可以这样处理 :
 类名::方法名() 或 parent::方法名()
举例 
class A{
  public $n1=90;
  //构造方法
  public function __construct(){
   echo "A __construct";
  }
 }
 class B extends A{
  function __construct(){
   echo "B __construct";
   //显式的调用父类的方法
   //A::__construct();
   parent::__construct();
  }
 }
 //创建B对象实例
 $b=new B();

(5)当一个子类的方法和父类的方法完全一样(public protected), 我们称为 方法的覆盖 (方法重写)。

①子类最多只能继承一个父类(指直接继承)
②子类可以继承其父类(或者超类)的 public ,protected修饰的变量(属性) 和 函数(方法). 
③在创建某个子类对象时,默认情况下不会自动调用其父类的构造函数,这点与java是不一样的。
④如果在子类中需要访问其父类的方法(构造方法/成员方法  方法的访问修饰符是public/protected),可以使用父类::方法名
(或者 parent::方法名) 来完成。
⑤如果子类(派生类)中的方法和父类(基类)方法相同,我们称为方法重写/方法覆盖]。

实例:
1). 判断下面代码是否正确
<?php 
 class A1 {
  public $n;
  protected $k;
  }
 class A2 {
 }
 class A3 extends A1,A2{
         
  public function test1(){
   echo "hello";
  }
 }
?>
错误,不能多重继承。
2). 判断下面的说法是不是正确
a. 子类可以继承父类的public 属性,private 方法。错误。
b. 子类不能继承父类的private 属性,但是可以继承private方法。错误。
c. 子类只能继承父类的public protected属性,但不能继承protected 方法。错误。
3). 下面的代码会输出什么内容
(1)
class Stu{
 public function __construct(){
  echo "stu()";
 }
}
class Pupil extends Stu{
 public function __construct(){
  Stu::__construct();
 }
}
$pupil=new Pupil();
输出:stu()
(2)
class Stu{
 public function __construct(){
  echo "stu()";
 }
}
class Pupil extends Stu{
 public function __construct(){
  PARENT::__construct();
 }
}
$pupil=new Pupil();
代码错误,不能大写;
(3)
class A{
 public function __construct(){
  echo "A()";
 }
}
class B extends A{
 public function __construct(){
  parent::__construct();
 }
}
class C extends B{
 public function __construct(){
  parent::__construct();
 }
}
$c=new C();
输出:A()
(4)
class A{
 public function __construct(){
  echo "A()";
 }
 private test(){
  echo "test()";
 }
}
class B extends A{
 public function __construct(){
  parent::test();
 }
}
$b=new B();
输出:代码错误,A类中private test(){
为私有的。不能调用。

四、PHP程序设计语言的多态
    “重载”是类的多态的一种实现。函数重载指一个标识符被用作多个函数名,且能够通过函数的参数个数或参数类型将这些同名的函数区分开来,调用不发生混淆。调用的时候,虽然方法名字相同,但根据参数表可以自动调用对应的函数。
    PHP5 虽然可以支持重载,但重载在具体实现上,和其他语言还有较大的差别。如果你试图定义多个同名函数(如下),那你的程序运行时将会报错,请看下面的一个案例:
class phpClass{
        public function __construct(){
        //do something}
        public funciton __construct($arg1){
        //do something}
}
势图定义两个构造函数。
class phpClass2{
        public function test1(){
        //do something}
        public funciton test1($arg1){
        //do something}
}
势图定义两个普通函数。

两个案例,均会报错,结论: 构造函数和成员函数,都不能重载.(创建实例,就会出效果,因为php的解释执行.)
    基本概念:函数名一样,通过函数的参数个数或者是参数类型不同,达到调用同一个函数名,但是可以区分不同的函数。
class  A{
 public function test1(){
 echo “test1”;
}
public function test1($a){
 echo “test1 hello”;
}
}
重载:
$a =new A();
$a->test1();
$a->test1(456);
上面的这用用法是不对,PHP会提示错误。

PHP5程序设计语言中如何通过魔术函数(__call)来实现方法重载的效果。
PHP5程序设计语言给我们提供了强大的‘魔术’函数, 使用这些‘魔术’函数, 我们也可以做到函数重载. 这里要用到函数是 __call。 
php程序设计语言中有以下魔术函数:__set __get  __construct __destruct __call  __toString __clone __sleep  __wakeup __isset __unset  __autoload 
php程序设计语言中有以下魔术常量:__LINE__ (所在行),  __FILE__(文件绝对路径还文件名),__FUNCTION__ , __CLASS__ ,__METHOD__

代码说明:
<?php
 class  A{
  public function test1($p){
   echo "接收一个参数";
   echo "<br/>接收到参数是";
   var_dump($p);
  }
  public function test2($p){
   echo "接收两个参数<br/>";
   var_dump($p);
  }
  //这些提供一个__call 
  //__call 是它一个对象调用某个方法,而该方法不存在,则系统会自动调用__call
  function __call($method,$p){
   var_dump($p);
   if($method=="test"){
    if(count($p)==1){
     $this->test1($p);
    }else if(count($p)==2){
     $this->test2($p);
    }
   }
  }
 }
 $a=new A();
 $a->test(1);//输出:接收一个参数。
 $a->test(56,90); //输出:接收两个参数。
?>

小结: php5程序设计语言默认情况下不直接支持方法重载,可以同__call魔术方法,模拟一个方法效果的效果。

五、PHP程序设计语言的方法重写/方法覆盖(override)
    既然子类可以继承父类的属性和方法,这样可以提高代码的复用性,这个很好,可以问题来了,假设现在我要求大家写三个类猫猫、狗狗、猪猪。我们知道这三个东东都是动物,动物必然存在相同的特点。根据类的抽象特征,我们可以把它们的相同点提取出来,形成一个父类 Animal,然后继承。
    当一个父类知道所有的子类都有一个方法,但是父类不能确定该方法究竟如何写,可以让子类去覆盖这个方法,具体用法如下:
<?php
 //抽象一个Animal类
 class Animal{
  public $name;
  protected $price;
  function cry(){
   echo "不知道动物怎么叫..";
  }
 }
 class Dog extends Animal{
  //覆盖
  function cry(){
   echo "小狗汪汪叫..";
  }
 }
 class Pig extends Animal{
  //覆盖
  function cry(){
   echo "哼哼叫..";
  }
 }
 //创建一个只狗
 $dog1=new Dog();
 $dog1->cry();
 $pig1=new Pig();
 $pig1->cry();
?>
    简单的说:方法重写就是子类有一个方法,和父类的某个方法的名称、参数个数一样(但是并不要求参数的名称一样),那么我们就说子类的这个方法重写了父类的那个方法。比如上个案例的 Cat 类中的 cry方法就重写/覆盖了Animal类的cry方法。
    如果在子类中需要访问其父类的方法(public/protected属性),可以使用“父类::方法名”或者“parent::方法名”来完成。
在实现方法覆盖的时候,访问修饰符可以不一样 //但是必须满足: 子类的访问范围>=父类的访问范围。
    多态体现在什么地方?
class Animal{
  public function cry(){
   echo '动物叫唤..';
  }
 }
 class Cat extends Animal{
  public  function cry(){
   echo "abc";
  }
 }
 $cat1=new Cat();
 $cat1->cry();

当子类没有覆盖父类的方法则 $cat1->cry() 调用的是父类,当子类覆盖了父类的方法,则调用自己的cry()。

class Animal{
public function cry(){
echo '动物叫唤..';}}
class Cat extends Animal{
protected function cry(){
  echo '猫猫叫唤..';Animal::cry();
}}
$cat1=new Cat();

结论: 报错
如果把Animal 的 cry() 也改成 protected 则允许可以成功
或者把Animal 改成protected 而Cat是public也可以运行成功!

【推荐阅读】
陈力:传智播客古代 珍宝币 泡泡龙游戏开发第34讲:PHP 封装、继承、多态

陈力:传智播客古代 珍宝币 泡泡龙游戏开发第34讲:PHP 封装、继承、多态相关推荐

  1. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第35讲:PHP 抽象类与接口

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第35讲:PHP 抽象类与接口 如果一个类使用abstract 来修饰,则该类就是抽象类.抽象方法是声明为abstract的,是不需要实现的,供子类继承且实现 ...

  2. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第22讲:PHP语法、数据类型(整型、布尔型、浮点型、字符串型)

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第22讲:PHP语法.数据类型(整型.布尔型.浮点型.字符串型) PHP语法是什么样的,有哪些数据类型,有些什么变量.本文对PHP语法.数据类型(整型.布尔型 ...

  3. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第48讲:PHP绘图技术

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第48讲:PHP绘图技术 php绘图坐标体系中,坐标原点位于左上角,以像素为单位.php绘图时,要创建画布.画出各种图形.输出图形.销毁图形(释放内存资源). ...

  4. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第26讲:PHP函数

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第26讲:PHP函数 什么是PHP函数,如何通过function定义一个函数,如何理解函数的调用过程.这些问题都是网站建设中经常遇到的程序设计问题.在进行网站 ...

  5. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第28讲:PHP数组

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第28讲:PHP数组 PHP程序设计语言中的数组如何创建,一维数组的引用,PHP数组变量,foreach语句,如何对数组进行排序等等知识都是贵阳网站建设中的主 ...

  6. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第30讲:PHP多维数组

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第30讲:PHP多维数组 在PHP程序设计语言中,如何创建二维数组呢,怎样使用二维数组,这些问题在网站建设中非常重要.二维数组的基本语法为: $a=array ...

  7. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第50讲:PHP中的xml编程

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第50讲:PHP中的xml编程 Xml是extensiable markup language的简称,包括文档声明.元素.属性.注释.CDATA区.特殊字符 ...

  8. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第十讲:深入理解盒子模型

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第十讲:深入理解盒子模型 摘要:通过前节<第九讲:块元素.行内元素.标准流.盒子模型>学习了前节介绍了贵阳网站建设中的DIV+CSS中类选择器.i ...

  9. 陈力:传智播客古代 珍宝币 泡泡龙游戏开发第38讲:PHP数据库编程mysql

    陈力:传智播客古代 珍宝币 泡泡龙游戏开发第38讲:PHP数据库编程mysql php程序设计语言为我们提供了mysql扩展库.mysqli扩展库.Pdo三种方式来操作mysql数据库.本文为贵阳网站 ...

最新文章

  1. python 计时_python怎么实现计时
  2. modbus 台达a2_驱控智造未来 台达重磅发布多款工业自动化新品
  3. 反应速度测试软件,用批处理实现的反应速度测试工具
  4. 今天算做正式开始SP开发吧,第一步当然是将down下来的资料好好地看一看,顺便也记下这些有用的地址...
  5. 分享《数字化建设地图》与《BI地图》,大数据知识点一次看过瘾
  6. request转发,response重定向,异步请求json数据输出到页面
  7. java中间件_uncode-mq 基于netty的轻量级java消息中间件
  8. 181124每日一句
  9. Java判定身份证号码的合法性
  10. 程序员出海创富的机会在哪里?三位专家给出具体建议
  11. 如何在Foobar2000中使用iPod
  12. Golang happen before
  13. JAVA 赛码网|笔试时输入输出的控制
  14. Innodb存储引擎-idb文件格式解析
  15. 我的世界启动器制作教程
  16. 直扩 单音干扰抑制 matlab,数学计算软件MATLAB资料集锦分享
  17. 一个基于BCH的付费电驴下载的设想
  18. 域名能查到服务器信息么,域名查服务器信息
  19. 帆软认证BI工程师题库
  20. MP3文件剪切丢失怎么恢复

热门文章

  1. [转]秒杀系统架构分析与实战
  2. Internet Download Manager2022中文版免费下载
  3. OMRON NB7触摸屏添加.h头文件
  4. Android NDK下STD库share static方式加载 (so库混乱调用问题)
  5. 我的世界虚拟人生mod服务器,我的世界还能捏脸?虚拟人生MOD,工作恋爱与结婚生子一步完成...
  6. 收银机服务器无响应,超市收银机出现死机你该怎么办(转载)
  7. 静态页面引入看板娘live2d
  8. java中的properJavaRDP实现远程桌面连接windows主机
  9. SQL Server 索引基础知识(7)----Indexing for AND(转自蝈蝈俊.net)
  10. 论如何提升学习的能力