zoukankan      html  css  js  c++  java
  • php抽象类、接口、traint详解

    PHP底层实现(http://blog.jobbole.com/94475/)

    一,抽象类:abstract

    abstract class  HeHe{
      public  $age=18;//可以定义属性
      public function say(){//可以方法实现        echo "i am say";    }    
      abstract public function run();//方法声明 不能有花括号,抽象类可以没有抽象方法
    }
     

    抽象类归纳总结:

    1定义为抽象的类不能被实例化。

    2任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。

    3抽象类可以没有抽象方法,但是抽象类依然不能被实例化,被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现

    4继承一个抽象类的时候,非抽象子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。

     例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。

    补充:

    1抽象类可以有成员属性

    2有人问:抽象方法是否可以定义为私有,答案是不可以,因为抽象接口的目的就是为了抽象出类模型用来继承,定义为私有,外部访问不到,偏移了设计目的会报错

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

    4抽象类可以继承抽象类,且不能重写抽象父类的抽象方法,否者会报错。这样的用法,可以理解为对抽象类的扩展,使用关键词extends,若重写抽象父类的抽象方法则会报错

    class Test extends HeHe{
       public $name;
       public function __construct($a){        
        $this->name=$a;
      }       
    public function run (){
        
    //注意:抽象方法必须实现------Fatal error: Class Test contains 1 abstract method
        and must therefore be declared abstract or implement the remaining methods echo $this->name;    
      } public function say($a){
    var_dump ($a);
      } }

     

    二,接口:interface

    interface goSchool{interface
       const NAME='xiaoming';
        /* const和define的区别:
        1、const用于类成员变量的定义,一经定义,不可修改。
        Define不可以用于类成员变量的定义,可用于全局常量。
        2、Const可在类中使用,define不能
        3、Const不能在条件语句中定义常量
       
    */        //接口可以定义常量,但是不能定义成员属性         //接口可以有一个或者多个成员方法       public function go_111();
    class Go implements goSchool{       public function go_111(){        
        echo 11111;    
      } }
    接口讲解:
    1使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容
    2接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的
    3接口中定义的所有方法都必须是公有,这是接口的特性,protected和private会报错(Fatal error: Access type for interface method
    4常量:接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。不建议在接口中定义常量,没有什么用处
    5要实现一个接口,使用 implements 操作符。非抽象类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称
    6可以同时继承抽象类和实现接口,extends要写在前面.
    7抽象类实现接口,不需要重新其中的方法
    8实现多个接口时,接口中的方法不能有重名
    9接口也可以继承,通过使用 extends 操作符接口可以继承另一个或多个接口,使用extends关键字,多个用 ',' 隔开,但是不能实现另一个接口,当然更不能继承抽象类
    10类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误
     
     

    三,特性:trait

     
    1如果说:继承可以纵向扩展一个类,那么trait就是横向扩展一个类功能;trait不能被实例化
    2trait在php5.4后才支持,是将trait里的代码copy一份到类中(理解这个可以避免很多错误)
    3Trait、基类和本类对同名属性或方法的处理:Trait中的方法或属性会覆盖 基类中的同名的方法或属性,而本类会覆盖Trait中同名的属性或方法
      (trait优先级:内部方法>trait>extend)
    <?php
    trait Dog{
        public $name="dog";
        public function drive(){
            echo "This is dog drive";
        }
        public function eat(){
            echo "This is dog eat";
        }
    }
    
    class Animal{
        public function drive(){
            echo "This is animal drive";
        }
        public function eat(){
            echo "This is animal eat";
        }
    }
    
    class Cat extends Animal{
        use Dog;
        public function drive(){
            echo "This is cat drive";
        }
    }
    $cat = new Cat();
    $cat->drive();//This is cat drive
    $cat->eat(); //This is dog eat
    ?>

    4一个类可以组合多个Trait,通过逗号相隔 use trait1,trait2

    5当不同的trait中,却有着同名的方法或属性,会产生冲突,可以使用insteadof或 as进行解决,insteadof 是进行替代,而as是给它取别名

    <?php
    trait trait1{
        public function eat(){
            echo "This is trait1 eat";
        }
        public function drive(){
            echo "This is trait1 drive";
        }
    }
    trait trait2{
        public function eat(){
            echo "This is trait2 eat";
        }
        public function drive(){
            echo "This is trait2 drive";
        }
    }
    class cat{
        use trait1,trait2{
            trait1::eat insteadof trait2;
            trait1::drive insteadof trait2;
        }
    }
    class dog{
        use trait1,trait2{
            trait1::eat insteadof trait2;
            trait1::drive insteadof trait2;
            trait2::eat as eaten;
            trait2::drive as driven;
        }
    }
    $cat = new cat();
    $cat->eat();//This is trait1 eat
    $cat->drive(); //This is trait1 drive
    $dog = new dog(); 
    $dog->eat(); //This is trait1 eat
    $dog->drive(); //This is trait1 drive
    $dog->eaten();//This is trait2 eat
    $dog->driven(); //This is trait2 drive
    ?>

    6as 还可以修改方法的访问控制

    <?php
    trait Animal{
        public function eat(){
            echo "This is Animal eat";
        }
    }
    
    class Dog{
        use Animal{
            eat as protected;//写成Animal::eat as protected 规范点
        }
    }
    class Cat{
        use Animal{
            Animal::eat as private eaten;
        }
    }
    $dog = new Dog();
    $dog->eat();//报错,因为已经把eat改成了保护
    
    $cat = new Cat();
    $cat->eat();//正常运行,不会修改原先的访问控制
    $cat->eaten();//报错,已经改成了私有的访问控制
    ?>

    7Trait也可以互相组合,还可以使用抽象方法,静态属性,静态方法等

    <?php
    trait Cat{
        public function eat(){
            echo "This is Cat eat";
        }
    }
    
    trait Dog{
        use Cat;
        public function drive(){
            echo "This is Dog drive";
        }
        abstract public function getName();
        
        public function test(){
            static $num=0;
            $num++;
            echo $num;
        }
        
        public static function say(){
            echo "This is Dog say";
        }
    }
    class animal{
        use Dog;
        public function getName(){
            echo "This is animal name";
        }
    }
    
    $animal = new animal();
    $animal->getName();//This is animal name
    $animal->eat(); //This is Cat eat
    $animal->drive(); //This is Dog Drive
    $animal::say(); //This is Dog say
    $animal->test(); //1
    $animal->test(); //2
    ?>
  • 相关阅读:
    c# 自定义事件和委托
    C#委托之个人理解(转)
    invokeRequired属性和 invoke()方法
    .NET(C#)连接各类数据库
    Mobile Web Development with ASP.NET 2.0
    移动飞信WEB发送服务接口
    4行C#代码打造专业数据库连接配置界面
    domino 中 UniversalID 和NoteID的区别
    VB中preserve的用法
    LOTUS Note ID 剖析
  • 原文地址:https://www.cnblogs.com/tkzc2013/p/10108383.html
Copyright © 2011-2022 走看看