陈力:传智播客古代 珍宝币 泡泡龙游戏开发第35讲:PHP 抽象类与接口
如果一个类使用abstract 来修饰,则该类就是抽象类。抽象方法是声明为abstract的,是不需要实现的,供子类继承且实现的。接口体现了程序设计的多态和高内聚低偶合的设计思想。贵阳网站建设的朋友必须要掌握抽象类和接口的知识。陈力:传智播客古代 珍宝币 泡泡龙游戏开发第35讲:PHP 抽象类与接口
一、PHP程序设计语言的抽象类
当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法[抽象方法],用abstract 来修饰该类 [抽象类]。
为什么设计抽象类这个技术?
在实际开发中,我们可能有这样一种类,是其它类的父类,但是它本身并不需要实例化,主要用途是用于让子类来继承,这样可以到达代码复用。同时利于项目设计者,设计类。
基本用法:
abstract class 类名{
//方法
//属性
}
如果一个类使用abstract 来修饰,则该类就是抽象类,如果一个方法被abstract修饰,则该方法就是抽象方法(抽象方法就不能有方法体)。
abstract class 类名{
abstract 修饰符 function 函数名(参数列表);
}
abstract class Animal{
public $name;
abstract public function cry();//抽象函数不能有函数体。
}
抽象类可以没有抽象方法,同时还可以有实现了的方法。
<?php
abstract class Animal{
public $name="abc";
protected $age;
//这个方法没有方法体,这个方法主要是为了让子类去实现。
abstract public function cry();
public function getName(){//这个方法是实现了的
return $this->name;
}
}
class Cat extends Animal{//实现了方法
public function cry(){
echo "猫猫叫唤..";
}
}
$cat1=new Cat();//创建一个子类实例
$cat1->cry();
echo $cat1->getName();
?>
如果一个类中,只要有抽象方法,则该类必须声明为abstract类。
abstract class A{
abstract function test();
}
echo "ok";
如果A类继承了一个抽象类B,则要求A类实现从B类继承的所有抽象方法。案例:
//这是一个抽象类
abstract class A{
abstract function test();
}
//B类要么自己抽象,或者实现从A类继承的抽象方法。
class B extends A{
function test(){
echo "我实现A:test()";
}
}
echo "hello";
抽象类注意事项:
①抽象类不能被实例化。
②抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法。
③一旦类包含了abstract方法,则这个类必须声明为abstract。
④抽象方法不能有函数体。
⑤如果一个类继承了某个抽象类,则它必须实现该抽象类的所有抽象方法。(除非它自己也声明为抽象类)。
二、PHP程序设计语言的接口
一个程序就是一个世界,在现实世界存在的情况,在程序中也会出现。接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。语法:
class 类名 implements 接口{
}
接口是更加抽象的抽象类,抽象类里的方法可以有方法体,接口里的所有方法都没有方法体。接口体现了程序设计的多态和高内聚低偶合的设计思想。
入门例子:
<?php
//使用程序模拟现实情况
//定义规范(方法/属性)
interface iUsb{
public function start();
public function stop();
}
//编写相机类,让它去实现接口
//1.当一个类实现了某个接口,则要求该类必须实现这个接口的所有方法。
class Camera implements iUsb{
public function start(){
echo "相机开始工作";
}
public function stop(){
echo "相机停止工作...";
}
}
//编写手机类
class Phone implements iUsb{
public function start(){
echo "手机开始工作";
}
public function stop(){
echo "手机停止工作...";
}
}
$camera1=new Camera();//使用
$camera1->start();
$camera1->stop();
echo "<br/>";
$phone1=new Phone();//手机对象
$phone1->start();
$phone1->stop();
?>
接口的使用基本语法:
interface 接口名{
//属性
//方法
}
接口的方法都不能有方法体。
如何去实现接口:
class 类名 implements 接口名1,接口2.{
}
接口作用就是声明一些方法,供其它类来实现。接口还体现编程中我们希望的效果高内聚低耦合的特点:
什么情况下可以考虑使用接口?软件设计人员在定规范、定下规范让别的程序员来实现。或者在多个类中,这些类是平级的关系,这些类都会去实现某个功能,只是实现的方式不一样。这种情况下也可以考虑使用接口。
比如:
//学生管理系统 (students)
//定义接口
interface StuManageInterface{
public function addStudent($stu);
public function delStudent($id);
public function updStudent($stu);
}
//三张在程序设计时
class StuManage {
public function tianjiaxuesheng(){
}
}
…
在程序设计时,张三使用了拼音的函数名。李四又使用了其它函数名。这样就不统一了,软件设计师此时可以定义接口,固定为addStudent函数名。其它人员只需要实现即可。
接口的细节说明:
(1)不能去实例化一个接口。
interface iUsb{}
$a=new iUsb(); (这种是错误的!)
(2)接口中的所有方法,都不能有方法体。
(3)一个类可以去实现多个接口,逗号隔开。
语法如下:
class 类名 implements 接口1,接口2{
}
(4)接口中可以有属性,但是必须是常量(并且是public)。
interface iUsb{
const A=90;
}
echo "ok".iUsb::A;
(5)接口的方法是public(默认就是public ),不能是protected 和private。
举例:
interface iUsb{
const A=90;
function test();
}
echo "ok".iUsb::A;
类和接口之间关系:
<?php
interface iUsb2{
public function a();
}
interface iUsb3{
public function b();
}
interface iUsb extends iUsb2,iUsb3{
const A=90;
function test();
}
class Class1 implements iUsb{
public function a(){
}
public function b(){
}
public function test(){
}
}
echo "ok".iUsb::A;
?>
从上面我们看出:一个接口不能继承其它的类,但是可以继承别的接口。一个接口可以继承多个其它的接口。当一个类去实现了某些接口,则必须实现所有接口的方法。
继承和实现接口的比较:
<?php
class Monkey{
public $age;
public $name;
public function climbing(){
echo "猴子会爬树..";
}
}
interface iBirdable{
public function fly();
}
interface iFishable{
public function swimming();
}
class LittleMonkey extends Monkey implements iBirdable,iFishable {
public function fly(){
echo "猴子会飞...";
}
public function swimming(){
echo "猴子会游泳..";
}
}
$littleMonkey=new LittleMonkey();
$littleMonkey->climbing();
$littleMonkey->fly();
$littleMonkey->swimming();
?>
可以认为实现接口是对单一继承的补充,可以在不破坏类层级关系的前提下,对某个类功能扩展。
php的继承是单继承,也就是一个类最多只能有一个父类,这种单继承的机制可保证类的纯洁性,比c++中的多继承机制简洁。
但是不可否认,对子类功能的扩展有一定影响,所以我们认为:
(1)实现接口可以看作是对继承的一种补充,还有一点,继承是层级式的,不太灵活。这种结构修改某个类就会打破这种继承的平衡,而接口就没有这样的麻烦,因为它只针对实现接口的类才起作用。
(2)实现接口可在不打破继承关系的前提下,对某个类功能扩展,非常灵活。
三、final关键字
final 中文意思:最后的,最终的。final可以修饰类或者方法。
①不希望父类的某个方法被子类重载(override)时,可以用final关键字修饰。
②不希望类被继承时,可以用final修饰。
如果贵阳网站建设中,希望某个类不被其它的类来继承(可能因为安全考虑...),可以使用final
<?php
final class A{
}
class B extends A{
}
echo "ok";
?>
如果我们希望某个方法,比如计算个人所得税的方法,不能子类改写,可以使用fianl 来修饰方法。
class A{
final public function getRate($salary){
return $salary*0.08;
}
}
class B extends A{
//不能去覆盖父类的getRate方法.
/*public function getRate($sal){
return $sal*0.01;
}*/
}
$b=new B();
echo $b->getRate(100);
注:final关键字不能去修饰属性。
四、const 关键字
const(constant) 中文意思:常量在某些情况下,程序员可能有这样的需求:
①当不希望一个成员变量被修改,希望该变量的值是固定不变的。这时可以用const 去修饰该成员变量,这样这个变量就自动成为常量。
基本用法是:
class A{
const 常量名=赋初值;
}
interface 接口名{
const 常量名=赋初值;
}
常量默认是public。
常量在使用时,通过类名::常量名; 接口名::常量
<?php
class A{
//常量在定义的时候,必须给初值.
//const 关键字前面不要带修饰符号.
const TAX_RATE=0.08;
public function payTax($val){
//常量不能修改.
//A::TAX_RATE=0.01;
//return $val*self::TAX_RATE; 【ok】
return $val*A::TAX_RATE; //【ok】
}
}
$a=new A();
echo $a->payTax(200);
?>
const使用注意事项:
①常量名一般字母全部大写 : TAXRATE
②在定义常量的同时,必须赋初值 const TAXRATE=1.1
③const关键字前不能用public/protected/private修饰。
④访问常量
在类的外部 类名::常量名
在类的内部,可以使用 类名::常量名,或者 self::常量名
⑤常量的值在定义的时候就初始化,以后就不能修改。
⑥常量可以被子类继承。
⑦一个常量是属于一个类的,而不是某个对象的。
const什么时候用?某些值是固定不变的,比如圆周率 3.1415926。
五、面向对象编程的综合案例
现在我们一起来完成php版本的计算器,从而加深对php的认识,为下一步学习做准备。先用两个页面来完该计算器: myCal.php(界面) myResult.php(计算)
知识点:
1. 如何接收php页面提交的数据,并处理。
2. php中如何使用javascript完成对数据合法性的校验。
MyCalView.php代码如下:
<html>
</head>
<title>我的计算器</title>
<script language="javascript">
function check(){
//js的内容 。。。。
var num1val=document.getElementById("num1").value;
var num2val=document.getElementById("num2").value;
if(isNaN(num1val)||isNaN(num2val)){
window.alert("num1和num2必须是数");
//如果返回false就不提交.
return false;
}
}
</script>
</head>
<h1>我的计算器</h1>
<form action="CalProcess.php" method="post" οnsubmit="return check()">
num1:<input type="text" id="num1" name="num1"><br/>
num2:<input type="text" id="num2" name="num2"><br/>
oper:
<select name="oper">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="submit" value="提交">
</form>
</html>
CalProcess.php源代码如下:
<?php
require_once "OperService.class.php";
//接收三个数
//isset
if(isset($_REQUEST['num1'])){
$num1=$_REQUEST['num1'];
}
if(isset($_REQUEST['num2'])){
$num2=$_REQUEST['num2'];
}
if(isset($_REQUEST['oper'])){
$oper=$_REQUEST['oper'];
}
//创建对象
$operService=new OperService();
echo $operService->getResult($num1,$num2,$oper);
?>
OperService.class.php源代码如下:
<?php
//定义了一个专门提供计算的类.
class OperService{
public function getResult($num1,$num2,$oper){
switch($oper){
case "+":
return $num1+$num2;
break;
case "-":
return $num1-$num2;
break;
case "*":
return $num1*$num2;
break;
case "/":
return $num1/$num2;
default:
echo "操作符错误";
}
}
}
?>
【推荐阅读】
一、PHP程序设计语言的抽象类
当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法[抽象方法],用abstract 来修饰该类 [抽象类]。
为什么设计抽象类这个技术?
在实际开发中,我们可能有这样一种类,是其它类的父类,但是它本身并不需要实例化,主要用途是用于让子类来继承,这样可以到达代码复用。同时利于项目设计者,设计类。
基本用法:
abstract class 类名{
//方法
//属性
}
如果一个类使用abstract 来修饰,则该类就是抽象类,如果一个方法被abstract修饰,则该方法就是抽象方法(抽象方法就不能有方法体)。
abstract class 类名{
abstract 修饰符 function 函数名(参数列表);
}
abstract class Animal{
public $name;
abstract public function cry();//抽象函数不能有函数体。
}
抽象类可以没有抽象方法,同时还可以有实现了的方法。
<?php
abstract class Animal{
public $name="abc";
protected $age;
//这个方法没有方法体,这个方法主要是为了让子类去实现。
abstract public function cry();
public function getName(){//这个方法是实现了的
return $this->name;
}
}
class Cat extends Animal{//实现了方法
public function cry(){
echo "猫猫叫唤..";
}
}
$cat1=new Cat();//创建一个子类实例
$cat1->cry();
echo $cat1->getName();
?>
如果一个类中,只要有抽象方法,则该类必须声明为abstract类。
abstract class A{
abstract function test();
}
echo "ok";
如果A类继承了一个抽象类B,则要求A类实现从B类继承的所有抽象方法。案例:
//这是一个抽象类
abstract class A{
abstract function test();
}
//B类要么自己抽象,或者实现从A类继承的抽象方法。
class B extends A{
function test(){
echo "我实现A:test()";
}
}
echo "hello";
抽象类注意事项:
①抽象类不能被实例化。
②抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法。
③一旦类包含了abstract方法,则这个类必须声明为abstract。
④抽象方法不能有函数体。
⑤如果一个类继承了某个抽象类,则它必须实现该抽象类的所有抽象方法。(除非它自己也声明为抽象类)。
二、PHP程序设计语言的接口
一个程序就是一个世界,在现实世界存在的情况,在程序中也会出现。接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。语法:
class 类名 implements 接口{
}
接口是更加抽象的抽象类,抽象类里的方法可以有方法体,接口里的所有方法都没有方法体。接口体现了程序设计的多态和高内聚低偶合的设计思想。
入门例子:
<?php
//使用程序模拟现实情况
//定义规范(方法/属性)
interface iUsb{
public function start();
public function stop();
}
//编写相机类,让它去实现接口
//1.当一个类实现了某个接口,则要求该类必须实现这个接口的所有方法。
class Camera implements iUsb{
public function start(){
echo "相机开始工作";
}
public function stop(){
echo "相机停止工作...";
}
}
//编写手机类
class Phone implements iUsb{
public function start(){
echo "手机开始工作";
}
public function stop(){
echo "手机停止工作...";
}
}
$camera1=new Camera();//使用
$camera1->start();
$camera1->stop();
echo "<br/>";
$phone1=new Phone();//手机对象
$phone1->start();
$phone1->stop();
?>
接口的使用基本语法:
interface 接口名{
//属性
//方法
}
接口的方法都不能有方法体。
如何去实现接口:
class 类名 implements 接口名1,接口2.{
}
接口作用就是声明一些方法,供其它类来实现。接口还体现编程中我们希望的效果高内聚低耦合的特点:
什么情况下可以考虑使用接口?软件设计人员在定规范、定下规范让别的程序员来实现。或者在多个类中,这些类是平级的关系,这些类都会去实现某个功能,只是实现的方式不一样。这种情况下也可以考虑使用接口。
比如:
//学生管理系统 (students)
//定义接口
interface StuManageInterface{
public function addStudent($stu);
public function delStudent($id);
public function updStudent($stu);
}
//三张在程序设计时
class StuManage {
public function tianjiaxuesheng(){
}
}
…
在程序设计时,张三使用了拼音的函数名。李四又使用了其它函数名。这样就不统一了,软件设计师此时可以定义接口,固定为addStudent函数名。其它人员只需要实现即可。
接口的细节说明:
(1)不能去实例化一个接口。
interface iUsb{}
$a=new iUsb(); (这种是错误的!)
(2)接口中的所有方法,都不能有方法体。
(3)一个类可以去实现多个接口,逗号隔开。
语法如下:
class 类名 implements 接口1,接口2{
}
(4)接口中可以有属性,但是必须是常量(并且是public)。
interface iUsb{
const A=90;
}
echo "ok".iUsb::A;
(5)接口的方法是public(默认就是public ),不能是protected 和private。
举例:
interface iUsb{
const A=90;
function test();
}
echo "ok".iUsb::A;
类和接口之间关系:
<?php
interface iUsb2{
public function a();
}
interface iUsb3{
public function b();
}
interface iUsb extends iUsb2,iUsb3{
const A=90;
function test();
}
class Class1 implements iUsb{
public function a(){
}
public function b(){
}
public function test(){
}
}
echo "ok".iUsb::A;
?>
从上面我们看出:一个接口不能继承其它的类,但是可以继承别的接口。一个接口可以继承多个其它的接口。当一个类去实现了某些接口,则必须实现所有接口的方法。
继承和实现接口的比较:
<?php
class Monkey{
public $age;
public $name;
public function climbing(){
echo "猴子会爬树..";
}
}
interface iBirdable{
public function fly();
}
interface iFishable{
public function swimming();
}
class LittleMonkey extends Monkey implements iBirdable,iFishable {
public function fly(){
echo "猴子会飞...";
}
public function swimming(){
echo "猴子会游泳..";
}
}
$littleMonkey=new LittleMonkey();
$littleMonkey->climbing();
$littleMonkey->fly();
$littleMonkey->swimming();
?>
可以认为实现接口是对单一继承的补充,可以在不破坏类层级关系的前提下,对某个类功能扩展。
php的继承是单继承,也就是一个类最多只能有一个父类,这种单继承的机制可保证类的纯洁性,比c++中的多继承机制简洁。
但是不可否认,对子类功能的扩展有一定影响,所以我们认为:
(1)实现接口可以看作是对继承的一种补充,还有一点,继承是层级式的,不太灵活。这种结构修改某个类就会打破这种继承的平衡,而接口就没有这样的麻烦,因为它只针对实现接口的类才起作用。
(2)实现接口可在不打破继承关系的前提下,对某个类功能扩展,非常灵活。
三、final关键字
final 中文意思:最后的,最终的。final可以修饰类或者方法。
①不希望父类的某个方法被子类重载(override)时,可以用final关键字修饰。
②不希望类被继承时,可以用final修饰。
如果贵阳网站建设中,希望某个类不被其它的类来继承(可能因为安全考虑...),可以使用final
<?php
final class A{
}
class B extends A{
}
echo "ok";
?>
如果我们希望某个方法,比如计算个人所得税的方法,不能子类改写,可以使用fianl 来修饰方法。
class A{
final public function getRate($salary){
return $salary*0.08;
}
}
class B extends A{
//不能去覆盖父类的getRate方法.
/*public function getRate($sal){
return $sal*0.01;
}*/
}
$b=new B();
echo $b->getRate(100);
注:final关键字不能去修饰属性。
四、const 关键字
const(constant) 中文意思:常量在某些情况下,程序员可能有这样的需求:
①当不希望一个成员变量被修改,希望该变量的值是固定不变的。这时可以用const 去修饰该成员变量,这样这个变量就自动成为常量。
基本用法是:
class A{
const 常量名=赋初值;
}
interface 接口名{
const 常量名=赋初值;
}
常量默认是public。
常量在使用时,通过类名::常量名; 接口名::常量
<?php
class A{
//常量在定义的时候,必须给初值.
//const 关键字前面不要带修饰符号.
const TAX_RATE=0.08;
public function payTax($val){
//常量不能修改.
//A::TAX_RATE=0.01;
//return $val*self::TAX_RATE; 【ok】
return $val*A::TAX_RATE; //【ok】
}
}
$a=new A();
echo $a->payTax(200);
?>
const使用注意事项:
①常量名一般字母全部大写 : TAXRATE
②在定义常量的同时,必须赋初值 const TAXRATE=1.1
③const关键字前不能用public/protected/private修饰。
④访问常量
在类的外部 类名::常量名
在类的内部,可以使用 类名::常量名,或者 self::常量名
⑤常量的值在定义的时候就初始化,以后就不能修改。
⑥常量可以被子类继承。
⑦一个常量是属于一个类的,而不是某个对象的。
const什么时候用?某些值是固定不变的,比如圆周率 3.1415926。
五、面向对象编程的综合案例
现在我们一起来完成php版本的计算器,从而加深对php的认识,为下一步学习做准备。先用两个页面来完该计算器: myCal.php(界面) myResult.php(计算)
知识点:
1. 如何接收php页面提交的数据,并处理。
2. php中如何使用javascript完成对数据合法性的校验。
MyCalView.php代码如下:
<html>
</head>
<title>我的计算器</title>
<script language="javascript">
function check(){
//js的内容 。。。。
var num1val=document.getElementById("num1").value;
var num2val=document.getElementById("num2").value;
if(isNaN(num1val)||isNaN(num2val)){
window.alert("num1和num2必须是数");
//如果返回false就不提交.
return false;
}
}
</script>
</head>
<h1>我的计算器</h1>
<form action="CalProcess.php" method="post" οnsubmit="return check()">
num1:<input type="text" id="num1" name="num1"><br/>
num2:<input type="text" id="num2" name="num2"><br/>
oper:
<select name="oper">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="submit" value="提交">
</form>
</html>
CalProcess.php源代码如下:
<?php
require_once "OperService.class.php";
//接收三个数
//isset
if(isset($_REQUEST['num1'])){
$num1=$_REQUEST['num1'];
}
if(isset($_REQUEST['num2'])){
$num2=$_REQUEST['num2'];
}
if(isset($_REQUEST['oper'])){
$oper=$_REQUEST['oper'];
}
//创建对象
$operService=new OperService();
echo $operService->getResult($num1,$num2,$oper);
?>
OperService.class.php源代码如下:
<?php
//定义了一个专门提供计算的类.
class OperService{
public function getResult($num1,$num2,$oper){
switch($oper){
case "+":
return $num1+$num2;
break;
case "-":
return $num1-$num2;
break;
case "*":
return $num1*$num2;
break;
case "/":
return $num1/$num2;
default:
echo "操作符错误";
}
}
}
?>
【推荐阅读】陈力:传智播客古代 珍宝币 泡泡龙游戏开发第35讲:PHP 抽象类与接口