php继承---trait代码复用

 思考:php中继承是单继承,如果某个类有成员要被其他类使用,就需要成为其他类的父类才行,这样可能会导致继承链会长,合适吗?

引入:从继承的角度出发,继承链可以解决问题,但是的确效率会打折扣,同时,如果某些功能是共性使用,但是并不符合继承条件(不属于同一类)

那么使用继承也有所违背面上对象规则,此时可以使用php提供的另外一种代码复用技术trait

 

trait代码复用【掌握】

定义:trait是为类似php的单继承语言而准备的一种代码复用机制,trait可以使单继承语言为了复用而不得不继承的尴尬,让面向对象更加纯粹

1.trait是一种类似class的关键字

<?php


// 定义trait
trait show{

}

2.trait内部可以像类一样拥有成员属性(包含静态),成员方法(包含静态),但不能有常量

<?php


// 定义trait
trait show{
    public $name;

    protected $host;                           //允许定义,但实际不用
    private $info; 

    public function show_time(){ 
        echo $this->info;
    }

    protected function showhost(){                //允许定义,但实际不用
        echo $this->name;
    }

    const pi=3.1415926;                //错误  trait中不能有常量
}

3.trait是用来实现代码的复用的,不可以被实例化也不可以被继承

<?php


// 定义trait
trait show{
    public $name;

    protected $host;                           //允许定义,但实际不用
    private $info; 

    public function show_time(){ 
        echo $this->info;
    }

    protected function showhost(){                //允许定义,但实际不用
        echo $this->name;
    }


}


new show();                //trait 不允许被实例化

4.trait是用来将公共代码提供给其他类使用的,而类要使用trait的掐你是加载对应的trait

<?php


// 定义trait
trait Show{
    public $name="d";
    public function show_time(){ 
        echo $this->name;
    }

}



//类中加载trait
class add{
    //加载:使用use关键字
    use Show;           //use 就表示将trait show中所有的东西拿到了当前类add中
}


//使用trait中的内容
$s=new add();
$s->show_time();                //show add类中自己没有show_time方法,但是因为使用了trait show 所以可用

5.一个类可以使用多个trait

<?php


// 定义trait
trait Show{
    public $name="d";
    public function show_time(){ 
        echo $this->name;
    }

}

trait get{
    public $age=18;

    public function get_age(){
        echo $this->age;
    }
}



//类中加载trait
class add{
    //加载:使用use关键字
    use Show;           //use 就表示将trait show中所有的东西拿到了当前类add中
    use get;
}


//使用trait中的内容
$s=new add();
$s->show_time();                //show add类中自己没有show_time方法,但是因为使用了trait show 所以可用
$s->get_age();

 6.如果同时引入的多个trait中有同名方法,那么会产生冲突:解决冲突的方法是使用insteadof代替处理以及对被代替的方法使用别名

<?php


// 定义trait
trait show{
    public $name="d";
    public function show_time(){ 
        echo $this->name;
    }

}

trait get{
    public $age=18;

    public function show_time(){
        echo $this->age;
    }
}



//类中加载trait
class add{

    // use get,show;                 //错误 2个trait存在同名的方法

    // 方案1 使用其中一个同名方法
    use get,show{
        // 意思 使用show中的show_time 代替get中的show_time,并且会被覆盖无法使用
        show::show_time insteadOf get;
        // 方案2 给get中的show_time取一个别名  就可以使用了。
        get::show_time as show_insteadostime;
    }
}

$s=new add();
$s->show_time();            //输出的是d  而不是18  代替成功
$s->show_insteadostime();       //显示18

7.同名覆盖问题:如果类中有与引入的trait同名成员,会有不同处理

  属性:不允许重名,即类中不允许定于与trait中同名的成员属性(静态属性也一样)

  方法:类覆盖trait

<?php


// 定义trait
trait show{
    public $name="d";
    public function show_time(){ 
        echo $this->name;
    }

}

trait get{
    public $age=18;

    public function show_time(){
        echo $this->age;
    }
}



//类中加载trait
class add{

    // use get,show;                 //错误 2个trait存在同名的方法

    // 方案1 使用其中一个同名方法
    use get,show{
        // 意思 使用show中的show_time 代替get中的show_time,并且会被覆盖无法使用
        show::show_time insteadOf get;
        // 方案2 给get中的show_time取一个别名  就可以使用了。
        get::show_time as show_insteadostime;
    }
}

$s=new add();
$s->show_time();            //输出的是d  而不是18  代替成功
$s->show_insteadostime();       //显示18

8.继承覆盖问题:如果类中在使用trait的同时,也是继承自父类,而trait中与父类中有同名方法,那么trait中将覆盖父类同名方法,如果要访问父类方法,

可以在trait同名方法中使用parent关键字访问父类同名方法。

<?php

// 代码复用
    trait posen{
        public $name="杜伟";
        public $age=31;

        public function show(){
         // 如果想用父类中的方法
         parent::show();
            echo $this->name.$this->age;
        }
    }


// 父类
class human{
    public function show(){

        echo 'human::show<hr>';
    }
 
}

// 定义子类
class son extends human{
    use posen;              
}

// 实例化
$s=new son();
$s->show();               //显示的是杜伟 31  trait中的方法会覆盖继承中父类的方法

9.另外,trait自己不能访问,只是用来给其他类提供代码复用的,因此允许类在使用trait时更高里面方法的访问控制权。在as 之后,使用目标访问修饰限定符。

<?php

// 代码复用
    trait posen{
        private function show(){
            echo '你看到我了';
        }
    }

class son{
    use posen{
        //因为我只是引用了一个show,如果是两个的话  需要具体的体现是哪个 posen::show(这个)
        show as public pshow;              
        //注意 as是用来起别名的,虽然没有同名show 但是系统认为已经存在,并且改变trait中show的访问权限为public 变成了一个新的方法,原来的方法不动。
    }              
}

// 实例化
$s=new son();
$s->pshow();           //调用别名方法

10.trait中可以使用抽象方法,用来规范使用类必须实现对应抽象方法,使用了欸要么为抽象类,要么就必须实现抽象方法

<?php

// 代码复用
    trait posen{
       abstract public function add();            //trait 定义抽象方法
    }


// 第一种方式
abstract class man{
    use posen;                          //抽象类可以不实现抽象方法
}

// 第二种
class son{
    use posen;
    public function add(){
        echo '实现了trait中的抽象方法';          //实现抽象方法
    }
                
}

总结:

  1.trait的hi一种类似class结构关键字,trait不能被实例化,可以拥有所有类成员结构

  2.trait是用来实现代码复用的,为其他类提供公共代码(方法),其他类如果使用trait用use关键字引入

  3.在了类中use是具体trait就相当于将trait内部的所有代码在类中写了一遍

  4.一个类中可以有多个trait,但是要注意同名问题

    同名方法可以使用insteadof来实现代替:一个trait中的同名方法代替另外一个,类就访问替代的那个

    同名方法可以在被替代之后使用as制作方法使用as制作方法别名:类就可以拥有两个方法

  5.类中在引入trait后,要注意与trait中的同名成员问题

    同名属性:不允许

    同名方法:允许,类中的方法会覆盖trait中的方法

  6.如果在使用trait的同时也继承其他类,那么trait中出现的同名方法会覆盖基类的同名方法

  7.类在使用trait时可以修改trait方法的控制级别,更严或这更宽松都可以,注意修改控制级别时使用的时别名机制,一定要改成别名:trait名::方法名 as 访问修饰限定符 别名;

  8.trait中可以使用抽象方法,那么使用该trait的类就必须本身为抽象类或者将抽象方法实现

  9.trait使用机制

    有公共代码要实现(方法),而这些方法可能在很多类中会用到

    公共代码不是属于某一类事务特有,而是很多事务都有(不符合继承)

 

posted @ 2020-02-13 14:44  WhiteSpace  阅读(978)  评论(0编辑  收藏  举报