php抽象类、interface、trait、final

版权声明:CopyRight @CSDN 码农Robin https://blog.csdn.net/weixin_41423450/article/details/90141113

一、抽象类

  1. 抽象类的定义

    任何一个类,如果它里面至少有一个方法被声明为抽象方法,那么这个类就必须被声明为抽象的,被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现,即抽象方法没有方法体。

    抽象类不能被实例化

    abstract class AbstractClass
    {
     // 强制要求子类定义这些方法
        abstract protected function getValue();
        abstract protected function prefixValue($prefix);
    
        // 普通方法(非抽象方法)
        public function printOut() {
            print $this->getValue() . "\n";
        }
    }
    
  2. 抽象类规则

    某个类只要至少含有一个抽象方法,就必须声明为抽象类

    抽象方法,不能含有方法体

    继承抽象类的子类,实现抽象方法的,访问权限不能低于该抽象方法

    继承抽象类的子类,如果不实现所有的抽象方法,那么该子类也为抽象类

  3. 应用要点

    抽象类的子类(子类为非抽象类),必须完全实现这个抽象类中的方法

    不能从抽象类创建对象,它的意义在于被继承(即抽象类不能被实例化)

    抽象类应至少有一个抽象方法,方法中没有方法体,抽象方法不必实现具体的功能,由子类来完成

    抽象类的方法可以有参数,也可以为空,若抽象方法有参数,那么子类的实现也必须有相同的参数个数

  4. 抽象类的实现

    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

  1. 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, ...
    {
        ......
    }
    
  2. interface规则

    接口不能实例化

    接口的属性必须是常量

    接口的方法必须是public【默认public】,且不能有函数体

    类必须实现接口的所有方法

    一个类可以同时实现多个接口,用逗号隔开

    接口可以继承接口【用的少】

  3. interface使用场景

    定规范,保持统一性;

    多个平级的类需要去实现同样的方法,只是实现方式不一样

  4. 接口和抽象类的区别

    接口是特殊的抽象类,也可以看做是一个模型的规范。接口与抽象类大致区别如下:

    一个子类如果 implements 一个接口,就必须实现接口中的所有方法(不管是否需要);如果是继承一个抽象类,只需要实现需要的方法即可。
    
    如果一个接口中定义的方法名改变了,那么所有实现此接口的子类需要同步更新方法名;而抽象类中如果方法名改变了,其子类对应的方法名将不受影响,只是变成了一个新的方法而已(相对老的方法实现)。
    
    抽象类只能单继承,当一个子类需要实现的功能需要继承自多个父类时,就必须使用接口。
    

三、trait

  1. 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;
        /* ... */
    }
    
  2. trait优先级

    从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 trait 的方法,而 trait 则覆盖了被继承的方法。

    即在当前类、trait、父类方法同名时,当前类的方法>trait方法>父类方法

    使用多个trait时,若存在同名方法,在不解决冲突时会报致命错误

  3. 多个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)

猜你喜欢

转载自blog.csdn.net/weixin_41423450/article/details/90141113