一、抽象类
-
抽象类的定义
任何一个类,如果它里面至少有一个方法被声明为抽象方法,那么这个类就必须被声明为抽象的,被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现,即抽象方法没有方法体。
抽象类不能被实例化
abstract class AbstractClass { // 强制要求子类定义这些方法 abstract protected function getValue(); abstract protected function prefixValue($prefix); // 普通方法(非抽象方法) public function printOut() { print $this->getValue() . "\n"; } }
-
抽象类规则
某个类只要至少含有一个抽象方法,就必须声明为抽象类
抽象方法,不能含有方法体
继承抽象类的子类,实现抽象方法的,访问权限不能低于该抽象方法
继承抽象类的子类,如果不实现所有的抽象方法,那么该子类也为抽象类
-
应用要点
抽象类的子类(子类为非抽象类),必须完全实现这个抽象类中的方法
不能从抽象类创建对象,它的意义在于被继承(即抽象类不能被实例化)
抽象类应至少有一个抽象方法,方法中没有方法体,抽象方法不必实现具体的功能,由子类来完成
抽象类的方法可以有参数,也可以为空,若抽象方法有参数,那么子类的实现也必须有相同的参数个数
-
抽象类的实现
abstract class AbstractClass { // 我们的抽象方法仅需要定义需要的参数 abstract protected function prefixName($name); } class ConcreteClass extends AbstractClass { // 我们的子类可以定义父类签名中不存在的可选参数 public function prefixName($name, $separator = ".") { if ($name == "Pacman") { $prefix = "Mr"; } elseif ($name == "Pacwoman") { $prefix = "Mrs"; } else { $prefix = ""; } return "{$prefix}{$separator} {$name}"; } } $class = new ConcreteClass; echo $class->prefixName("Pacman"), "\n"; echo $class->prefixName("Pacwoman"), "\n";
二、interface
-
interface的定义
如果一个抽象类里面的所有方法都是抽象方法,且没有声明变量,而且接口里面所有的成员都是 public 权限的,那么这种特殊的抽象类就叫interface。
接口使用关键字 interface 来定义,并使用关键字 implements 来实现接口中的方法,且必须完全实现。
//定义接口 interface User{ function getDiscount(); function getUserType(); } //VIP用户 接口实现 class VipUser implements User{ // VIP 用户折扣系数 private $discount = 0.8; function getDiscount() { return $this->discount; } function getUserType() { return "VIP用户"; } } class Goods{ var $price = 100; var $vc; //定义 User 接口类型参数,这时并不知道是什么用户 function run(User $vc){ $this->vc = $vc; $discount = $this->vc->getDiscount(); $usertype = $this->vc->getUserType(); echo $usertype."商品价格:".$this->price*$discount; } } $display = new Goods(); $display ->run(new VipUser); //可以是更多其他用户类型
实现多个接口
class 子类 extends 父类 implemtns 接口1, 接口2, ... { ...... }
-
interface规则
接口不能实例化
接口的属性必须是常量
接口的方法必须是public【默认public】,且不能有函数体
类必须实现接口的所有方法
一个类可以同时实现多个接口,用逗号隔开
接口可以继承接口【用的少】
-
interface使用场景
定规范,保持统一性;
多个平级的类需要去实现同样的方法,只是实现方式不一样
-
接口和抽象类的区别
接口是特殊的抽象类,也可以看做是一个模型的规范。接口与抽象类大致区别如下:
一个子类如果 implements 一个接口,就必须实现接口中的所有方法(不管是否需要);如果是继承一个抽象类,只需要实现需要的方法即可。 如果一个接口中定义的方法名改变了,那么所有实现此接口的子类需要同步更新方法名;而抽象类中如果方法名改变了,其子类对应的方法名将不受影响,只是变成了一个新的方法而已(相对老的方法实现)。 抽象类只能单继承,当一个子类需要实现的功能需要继承自多个父类时,就必须使用接口。
三、trait
-
trait的定义
Trait 和 Class 相似,但仅仅旨在用细粒度和一致的方式来组合功能。 无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个 Class 之间不需要继承。
trait ezcReflectionReturnInfo { function getReturnType() { /*1*/ } function getReturnDescription() { /*2*/ } } class ezcReflectionMethod extends ReflectionMethod { use ezcReflectionReturnInfo; /* ... */ } class ezcReflectionFunction extends ReflectionFunction { use ezcReflectionReturnInfo; /* ... */ }
-
trait优先级
从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。
即在当前类、trait、父类方法同名时,当前类的方法>trait方法>父类方法
使用多个trait时,若存在同名方法,在不解决冲突时会报致命错误
-
多个trait
通过逗号分隔,在use声明列出多个trait,可以都插入到一个类中
trait Hello { public function sayHello() { echo 'Hello '; } } trait World { public function sayWorld() { echo 'World'; } } class MyHelloWorld { use Hello, World; public function sayExclamationMark() { echo '!'; } } $o = new MyHelloWorld(); $o->sayHello(); $o->sayWorld(); $o->sayExclamationMark(); # Hello World!
四、final
如果父类中的方法被声明为 final,则子类无法覆盖该方法。如果一个类被声明为 final,则不能被继承。
class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}
final public function moreTesting() {
echo "BaseClass::moreTesting() called\n";
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo "ChildClass::moreTesting() called\n";
}
}
// Results in Fatal error: Cannot override final method BaseClass::moreTesting()
final class BaseClass {
public function test() {
echo "BaseClass::test() called\n";
}
// 这里无论你是否将方法声明为final,都没有关系
final public function moreTesting() {
echo "BaseClass::moreTesting() called\n";
}
}
class ChildClass extends BaseClass {
}
// 产生 Fatal error: Class ChildClass may not inherit from final class (BaseClass)