你对PHP抽象类和接口还有疑问吗?

目录

抽象类

接口

抽象类与接口的区别:


对于面向对象开发,抽象类与接口这两个东西是比较难理解的。也是面试经常问到的一个问题。

抽象类

在说抽象类之前,先了解一下抽象方法。

抽象方法没有方法实体的方法即为抽象方法,用abstract来修饰 abstract function abc();

抽象类:任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。(抽象类可以没有抽象方法,但是抽象类依然不能被实例化)被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。用abstract来修饰 abstract class A {};

抽象类不能被实例化。在抽象类中,即便全是具体方法,也不能够实例化。

理解一下:首先知道什么是抽象方法,即没有方法体的方法,然后理解抽象类,一个类中只要包含了抽象方法就是抽象类,但是抽象类中可以没有抽象方法。

 总结一下抽象类:

1.抽象类是通过 abstract 关键字来定义的,用关键字 extends 实现继承;

2.抽象类可以有属性、普通方法、抽象方法

3.抽象类内不一定有抽象方法,但有抽象方法的类,则必是抽象类

4.抽象类不能被实例化,只有非抽象类继承后才可实例化;

5.非抽象子类继承必须定义父类中的所有抽象方法

6.非抽象子类中继承方法的访问权限必须和父类一样或更宽松。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的;

7.抽象类可以继承抽象类,且不能重写抽象父类的抽象方法,否则报错。这样的用法,可以理解为对抽象类的扩展;

8.此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数(类似function eat(a,a,b=1)中的$b就是可选参数),而父类抽象方法的声明里没有,则两者的声明并无冲突。这也适用于 PHP 5.4 起的构造函数。在 PHP 5.4 之前的构造函数声明可以不一样的。

代码理解一下:

/**
 * 定义一个抽象类,可以有属性、普通方法、抽象方法
 */
abstract class A {
	//属性
	public $name;

	//抽象方法,强制要求非抽象子类继承这些方法,注意没有有{}
	abstract public function name();

	abstract protected function age($age);

	//普通方法
	public function say() {
		echo 'I am from A;';
	}
}

/**
 * 抽象类可以继承抽象类,且不能重写抽象父类的抽象方法
 */
abstract class B extends A{

	//抽象方法
	abstract protected function height();

	//普通方法
	public function hello() {
		echo 'I am from B;';
	}
}

/**
 * 定义非抽象类继承抽象类,必须定义父类中的所有抽象方法,且访问权限要与父类一致或宽松
 */
class C extends B {

	//定义父类中的所有抽象方法,且访问权限要与父类一致或宽松
	public function name() {
		echo 'I am from C, my name is '. $this->name;
	}

	//父类该方法是protected,子类可以是public 或 protected
	public function age($age) {
		echo 'I am from C,my age is ' . $age;
	}

	//父类没有参数,子类可以定义一个可选参数
	protected function height($height = 180) {
		echo 'I am from C,my height is ' . $height;
	}

	public function info($height = 180) {
		$this->height($height);
	}

}

$obj = new C();
$obj->name = 'jon';

$obj->name();	//I am from C, my name is jon
$obj->age(20);	//I am from C,my age is 20
$obj->info(170);	//I am from C,my age is 170
$obj->info();	//I am from C,my age is 180
$obj->say();	//I am from A
$obj->height();//会报致命错误。被定义为受保护的类成员则可以被其自身以及其子类和父类访问

接口

接口:没有主体代码的方法定义组成的集合体。可以被其他类实现或被其他接口继承。

接口可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。

总结一下接口:

1.接口通过 interface 来定义;

2.接口中定义的所有方法都必须是公有,这是接口的特性,protected和private会报错(Fatal error: Access type for interface method),非抽象类实现接口方法必须是public;

3.要实现一个接口,使用 implements 操作符。非抽象类中必须实现接口中定义的所有方法,否则会报一个致命错误;

4.接口可以继承另一个或多个接口,使用 extends 关键字,多个用 ‘,’ 隔开,但是不能实现另一个接口,当然更不能继承抽象类

5.可以同时继承抽象类和实现接口extends 要写在前面

6.抽象类可以实现接口,且可以不实现其中的方法

7.接口中可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。(不建议这样用,实在想不到有什么意义,也容易产生和抽象类的混淆)。

代码理解一下:

/**
 * 定义接口,
 */
interface A {

	//可以定义常量
	const PI = 3.14;

	//定义方法,没有方法体,必须是共有的
	public function say();

	public function show();

}

/**
 * 定义接口B
 */
interface B {

	 public function hello();
}

/**
 * 定义抽象类
 */
abstract class H {

	abstract public function info();
}

/**
 * 非抽象类实现接口,必须定义接口中的所有方法,可以实现多个接口用','隔开
 */
class X implements A,B {

	public function say() {
		echo 'I am from calss X method say';
	}

	public function show() {
		echo 'I am from calss X method say';
	}

	public function hello() {
		echo 'I am from calss X method hello';
	}

}

$obj = new X();
$obj->say();	//I am from calss X method say


/**
 * 可以同时继承抽象类和实现接口,extends 要写在前面;
 */
class Y extends H implements A,B {

	public function info(){
		echo 'I am from calss Y method info';
	}

	public function say() {
		echo 'I am from calss Y method say';
	}

	public function show() {
		echo 'I am from calss Y method say';
	}

	public function hello() {
		echo 'I am from calss Y method hello';
	}
}

$obj1 = new Y();
$obj1->info();	//I am from calss Y method info


/**
 * 抽象类实现接口,可以不实现其中的方法
 */
abstract class Z implements A {

	public function say() {
		echo 'I am from calss Z method say';
	}
}

/**
 * 非抽象类继承抽象类,要实现抽象类和接口中的方法
 */
class M extends Z {

	public function show() {
		echo 'I am from calss M method show';
	}
}

$obj2 = new M();
$obj2->say();	//I am from calss Y method info

抽象类与接口的区别:

抽象类与接口的相同点:

1.都是用于声明某一种事物,规范名称、参数,形成模块,未有详细的实现细节;

2.都是通过类来实现相关的细节工作

3.语法上,抽象类的抽象方法与接口一样,不能有方法体,即{}符号;

4.都可以用继承,接口可以继承接口形成新的接口,抽象类可以继承抽象类从而形成新的抽象类。

抽象类与接口的不同点:

1.抽象类可以有属性、普通方法、抽象方法,但接口不能有属性、普通方法,可以有常量

2.抽象类内未必有抽象方法,但接口内一定会有“抽象”方法;

3.语法上有不同,抽象类用abstract关键字在类前声明,且有class声明为类,接口是用interface来声明,但不能用class来声明,因为接口不是类;

4.抽象类的抽象方法一定要用abstract来声明,而接口则不需要;

5.抽象类是用extends关键字让子类继承父类后,在子类实现详细的抽象方法。而接口则是用implements让普通类在类里实现接口的详细方法,且接口可以一次性实现多个方法,用逗号分开各个接口即可;

6.抽象类的抽象方法的访问权限可以是public、protected接口的方法必须是public

总结一句话:

抽象类一般用来定义一类实体是什么,它包含了属性、抽象方法和非抽象方法。接口用来定义一类实体能做什么,一般认为它只有抽象方法,常量极少用到。

当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。

 

以上总结如有错误,欢迎指出更正。另外,本篇文章不做任何商业用途,仅方便自己日后查阅。同时也希望能够帮助其他小伙伴~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值