🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 面向对象的三大特征: **²  封装 抽象:简单理解,我们在定义一个类的时候,实际上就是把一类事物的共有属性和行为提取出来,形成一个物理模型,这种研究问题的方法叫做抽象。 封装:就是把抽象的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(成员方法),才能对数据进行操作。 那么在PHP中如何实现这种类型的控制呢!请看下面的小程序,不能随便查看人的年龄,工资等隐私。 访问控制修饰符 PHP提供三种访问控制修饰符皓来控制方法和变量(属性)的访问权限。 <table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top"><p align="left">Public</p></td><td valign="top"><p align="left">表示全局,类内部,外部和子类都可以访问</p></td></tr><tr><td valign="top"><p align="left">protected</p></td><td valign="top"><p align="left">表示受保护的,只有本类和子类可以访问</p></td></tr><tr><td valign="top"><p align="left">Private</p></td><td valign="top"><p align="left">表示私有的,只有本类的内部可以使用</p></td></tr></tbody></table> 下面是总结的使用范围 <table border="1" cellspacing="0" cellpadding="0"><tbody><tr><td valign="top"><p align="left"> </p></td><td valign="top"><p align="left">Public</p></td><td valign="top"><p align="left">Protected</p></td><td valign="top"><p align="left">private</p></td></tr><tr><td valign="top"><p align="left">全局</p></td><td valign="top"><p align="left"><span style="background:red">※</span></p></td><td valign="top"><p align="left"> </p></td><td valign="top"><p align="left"> </p></td></tr><tr><td valign="top"><p align="left">继承</p></td><td valign="top"><p align="left"><span style="background:red">※</span></p></td><td valign="top"><p align="left"><span style="background:red">※</span></p></td><td valign="top"><p align="left"><span style="background:red"> </span></p></td></tr><tr><td valign="top"><p align="left">本类</p></td><td valign="top"><p align="left"><span style="background:red">※</span></p></td><td valign="top"><p align="left"><span style="background:red">※</span></p></td><td valign="top"><p align="left"><span style="background:red">※</span></p></td></tr></tbody></table> Ø  如果一个方法没有设置访问修饰符,默认是public Ø  属性必须制定访问修饰符 Ø  成员内方法之间也可以相互调用,但是使用this ~~~ function test1(){ $this->test2(); } private function test2(){ echo "我是一名程序猿,转行学习,求大家多多指教"; } ~~~ ###如何访问protectedprivae修饰变量? ~~~ //通过下面的方法来访问protected private变量 //查看薪水: public function getSalary($name,$passwd){ if($name=="jsh" && $passwd=="1234567a"){ echo $this->salary; }else{ echo "输入用户名或密码错误,无法访问"; } } //修改年龄 public function setAge($age){ if($age>0&&$age<120){ $this->age=$age; }else{ echo "设置年龄不符合要求"; } } //查看年龄 public function getAge($name,$passwd){ if($name=="jsh" && $passwd=="1234567a"){ echo $this->age; }else{ echo "输入用户名或密码错误,无法访问"; } } ~~~ Ø  从上面可以很容易看出,对访问protected private修饰的变量提供了上述的访问方法,并且增加了验证! PHP设计者提供下面的方法: ~~~ <?php class A{ private $n1; private $n2; private $n3; private $n4; //使用__set方法来设置所有的属性 function __set($pro_name,$pro_val){ $this->pro_name=$pro_val; } //使用__get方法来获得所有的属性 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=222; echo $a1->n2; //结果:hello || 222 ?> ~~~ 上面的方法和public 使用时一样的,所以基本来对我们编程来说这种写法没有什么用途的。 代码一: ~~~ <?php //封装实例: class Person{ public $name; protected $age; private $salary; public function __construct($name,$age,$salary){ $this->name=$name; $this->age=$age; $this->salary=$salary; } //成员方法 public function showInfo(){ //三种访问控制修饰符号在本类中都可以访问 echo $this->name."||".$this->age."||".$this->salary; } //通过下面的方法来访问protected private变量 //查看薪水: public function getSalary($name,$passwd){ if($name=="jsh" && $passwd=="1234567a"){ echo $this->salary; }else{ echo "输入用户名或密码错误,无法访问"; } } //修改年龄 public function setAge($age){ if($age>0&&$age<120){ $this->age=$age; }else{ echo "设置年龄不符合要求"; } } //查看年龄 public function getAge($name,$passwd){ if($name=="jsh" && $passwd=="1234567a"){ echo $this->age; }else{ echo "输入用户名或密码错误,无法访问"; } } function test1(){ $this->test2(); } private function test2(){ echo "我是一名程序猿,转行学习,求大家多多指教"; } } $p1=new Person("阿辉",29,1000); //访问阿辉的年龄及薪水,有如下错误!private 是不能被外部访问的 // echo $p1->age.$p1->salary; //Fatal error: Cannot access private property Person::$age in /var/myphp/class/fengzhuang.php on line 18 //查看薪水 echo $p1->name."薪水是:"; $p1->getSalary("jsh","1234567a"); echo "<br/>"; //设置年龄,查看年龄 $p1->setAge(28); echo $p1->name."年龄是:"; $p1->getAge("jsh","1234567a"); echo "<br/>"; $p1->test1(); /***********输出结果*********** *阿辉薪水是:1000 *阿辉年龄是:28 *我是一名程序猿,转行学习,求大家多多指教 **************************/ ?> ~~~ ### 继承: ~~~ <?php //应用场景,开发一套学生管理系统(Pupil Graduate,...) /*************************** class Pupil{ public $name; private $age; private $grade; //构造方法 public function __construct($name,$age,$grade){ $this->name=$name; $this->age=$age; $this->grade=$grade; } //输入学生信息的方法 public function showInfo(){ echo $this->name."||".$this->age."||".$this->grade."<br/>"; } //考试方法 public function testing(){ echo "小学生考试<br/>"; } } class Graduate{ public $name; private $age; private $grade; //构造方法 public function __construct($name,$age,$grade){ $this->name=$name; $this->age=$age; $this->grade=$grade; } //输入学生信息的方法 public function showInfo(){ echo $this->name."||".$this->age."||".$this->grade."<br/>"; } //考试方法 public function testing(){ echo "研究生考试<br/>"; } } //考虑上述有很多共同点,不如年龄,名字,分数等等,这样就造成 //代码的复用性不高,代码的可维护性比较低, ****************************/ //解决方案,引入继承方法。 //父类 class Stu{ public $name; private $age; private $grade; //构造方法 public function __construct($name,$age,$grade){ $this->name=$name; $this->age=$age; $this->grade=$grade; } //输入学生信息的方法 public function showInfo(){ echo $this->name."||".$this->age."||".$this->grade."<br/>"; } } //子类 小学生 class Pupil extends Stu{ //考试方法 public function testing(){ echo "小学生考试<br/>"; } } //子类,研究生 class Graduate extends Stu{ //考试方法 public function testing(){ echo "研究生考试<br/>"; } } $pupil1=new Pupil("阿辉",28,99); $pupil1->showInfo(); $pupil1->testing(); $gra1=new Graduate("佩佩",29,89); $gra1->showInfo(); $gra1->testing(); /******输出结果**** *阿辉||28||99 *小学生考试 *佩佩||29||89 *研究生考试 **************/ ?> ~~~ 上面的代码,我们简单了解到继承方法的使用,引入继承方法的好处,可以解决代码复用,让我们的变成更加靠近人类的思维,当多个了存在相同的属性和方法是,可以从这些类中抽象出父类,在父类中定义这些相同的类或者方法,所有的子类不需要重新定义这些属性和方法,只需要通过 class 子类名 extends 父类名{ }  这样,子类就会自动永远父类定义的属性和方法。  细节讨论: 1)父类的那些属性(变量)、方法被子类继承了? 父类的public修饰符的属性和方法,protected修饰符的属性和方法被子类继承了。父类的private修饰符的属性和方法不能被子类继承。 2) 子类最多只能继承一个父类(直接继承) 3) 子类可以继承去父类的public protected修饰的属性和函数方法   4)在创建某个子类对象时,默认情况下不会自动调用其父类的构造方法,这点和JAVA不同。 ~~~ <?php //继承方法测试 class A{ public $name=90; public function __construct(){ echo "A __construct<br/>"; } } class B extends A{ public function ___construct(){ echo "B __construct<br/>"; } } $b=new B(); ?> ~~~ 上面的PHP会输出什么? 居然输出的是B __construct    5) 如果子类需要访问父类的方法(构造、成员方法,方法修饰符是public,protected)可以使用父类::方法名 或者parent::方法名)来完成。 ~~~ <?php //继承方法测试 class A{ public $name=90; public function __construct(){ echo "A __construct<br/>"; } } class B extends A{ public function __construct(){ //A::__construct(); parent::__construct(); } } $b=new B(); ?> ~~~ ### 重载 基本概念: 函数名一样,可以通过函数的参数个数或者参数类型的不同,达到嗲用同意函数名,但可以区分不同的函数。 1)PHP中 默认是不知道方法重载的 2)PHP可以 通过__call魔术方法,模拟一个方向的效果。 ~~~ <?php class A{ public function test1($p){ echo "输入一个参数<br/>"; var_dump($p); echo "<br/>"; } public function test2($p){ echo "输入二个参数<br/>"; var_dump($p); } function __call($method,$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(1,2); /* 输入一个参数 array(1) { [0]=> int(1) } 输入二个参数 array(2) { [0]=> int(1) [1]=> int(2) */ ?> ~~~ ### 方法覆盖: ~~~ <?php //抽象一个动物类 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(); ?> ~~~ ###  方法重写细节讨论 1、 要实现重写,要求子类的那个方法的名字和参数列表一模一样 2、如果子类要去调用父类的某个方法,前提是父类方法必须要public或者protected。在子类中可以使用  父类::方法名 或者parent::方法名)来完成。 3、在是先方法覆盖的时候,访问修饰符可以不一样。但是必须满足,子类的范围一定要大于等于父类的范围 ²  抽象类 为什么设计抽象类这个技术 1、在实际开饭中,我们可能有这样一种类,是其他类的父类,但是它本身并不需要实例化。主要用于子类来继承。这样可以达到代码复用作用,同时利于项目设计者设计类 2、如果一个类使用abstract修饰了,这个类就是抽象类 如果一个方法被abstract修饰了,这个抽象方法就不能有方法体; 1、  抽象类可以没有抽象方法,同时还有有实现了的方法,可以被子类继承。 2、  一个类中,只有有抽象方法,则该类必须声明为抽象类,否则会报错! 3、  如果一个类继承了某个抽象类,则要求子类必须实现从父类继承的所有抽象类,或者子类也是抽象类。 ~~~ <?php //抽象一个动物类 abstract class Animal{ public $name; protected $price; //这个方法没有方法体,主要为了给子类来覆盖 abstract public function cry(); } class Dog extends Animal{ //覆盖(逻辑上的覆盖) function cry(){ echo "小狗叫12。。。。"; } } class Pig extends Animal{ function cry(){ echo "小猪叫1234。。。。"; } } //创建一只狗 $dog1=new Dog(); $dog1->cry(); $pig1=new Pig(); $pig1->cry(); ?> ~~~