Blogger Information
Blog 42
fans 3
comment 2
visits 93663
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
抽象类,对象接口,匿名类,trait,final关键字
Whitney的博客
Original
2698 people have browsed it

一、抽象类

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

继承一个抽象类的时候子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为轻松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者共有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如:子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。

实例

<?php
abstract class AbstractClass{

    //强制要求子类中***定义这些方法
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);
    abstract protected function prefixName($name);

    //普通方法(非抽象方法)
    public function printOut(){
        print $this->getValue()."\n";
    }

}

class ConcreteClass1 extends AbstractClass{
    protected function getValue(){
        return "ConcreteClass1";
    }

    public function prefixValue($prefix){
        return "{$prefix}ConcreteClass1";
    }

    //我们的子类可以定义父类签名中不存在的可选参数
    public function prefixName($name,$separator = '.'){
        if($name == 'Pacman'){
            $prefix = "Mr";
        }elseif($name == 'Pacwoman'){
            $prefix = "Mrs";
        }else{
            $prefix = "";
        }

        return "{$prefix}{$separator}{$name}";
    }

}

class ConcreteClass2 extends AbstractClass{
    public function getValue(){
        return "ConcreteClass2";
    }

    public function prefixValue($prefix){
        return "{$prefix}ConcreteClass2";
    }

    //若该方法不声明,则会报错
    public function prefixName($name){

    }

}

$class1 = new ConcreteClass1();
$class1->printOut(); //ConcreteClass1
echo $class1->prefixValue("F00_")."\n"; // F00_ConcreteClass1
echo $class1->prefixName("Pacman"), "\n"; //Mr.Pacman


$class2 = new ConcreteClass2();
$class2->printOut();//ConcreteClass2
echo $class2->prefixValue("F00_")."\n"; //F00_ConcreteClass2
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

二、对象接口

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

接口是通过interface关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。

接口中定义的所有方法都必须公有,这是接口的特性。

要实现一个接口,使用implements操作符。类中必须实现接口中定义的所有方法,否则会报致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。

实现多个接口时,接口中的方法不能有重名。

接口也可以继承,通过使用extends操作符。

接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口覆盖。

实例

<?php
interface a{
    //接口常量不能被覆盖
    const param = 'Interface constant';
    public function foo();
}

interface b{
    public function bar();
}

interface c extends a,b{
    public function baz();
}
class d implements c{
    public function foo(){
        echo a::param;
    }

    public function bar(){

    }

    public function baz(){

    }
}

$d =new d();
$d->foo();//Interface constant

?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

三、匿名类

PHP 7 开始支持匿名类。匿名类很有用,可以创建一次性的简单对象。

可以传递参数到匿名类的构造器,也可以扩展(extend)其他类。实现接口(implement interface),以及像其他普通的类一样使用trait:

实例

<?php

class SomeClass{}
interface SomeInterface{}
trait SomeTrait{}

var_dump(new class(10) extends SomeClass implements SomeInterface{
    private $num;
    public function __construct($num){
        $this->num = $num;
    }
    
    use SomeTrait;
});
//object(class@anonymous)#1 (1) { ["num":"class@anonymous":private]=> int(10) }

?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

匿名类被嵌套进普通Class后,不能访问这个外部类(outer class)的private(私有)、protected(受保护)方法或属性。为了访问外部类(Outer class)protected属性或方法,匿名类可以extend(扩展)此外部类。为了使用外部类(Outer class)的private属性,必须通过构造器传进去:

实例

<?php
class Outer{
    private $prop = 1;
    protected $prop2 = 2;

    protected  function func1(){
        return 3;
    }

    public function func2(){
        return new class($this->prop) extends Outer{
            private $prop3;

            public function __construct($prop){
                $this->prop3 = $prop;
            }

            public function func3(){
                echo $this->prop2 ;//2
                 
                echo $this->prop3 ;//1
                 
                echo $this->func1();//3
                 
                echo $this->prop2 + $this->prop3 + $this->func1();//6
            }
        };
    }
}

(new Outer)->func2()->func3();
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

四、trait

1、trait是为类似PHP的单继承语言而准备的一种代码复用机制。trait为了减少单继承语言的限制,使开发人员能够自由地在不同层次结构内独立的类中复用method。

trait和class类似,但仅仅旨在用细粒度和一致的方式来组合功能。无法通过trait自身来实例化。它为传统继承增加了水平特性的组合;也就是说,应用的几个class之间不需要继承。

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

实例

<?php
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait SayWorld {
    public function sayHello() {
        parent::sayHello();
        echo 'World!';
    }
}

class MyHelloWorld extends Base {
    use SayWorld;
}

$o = new MyHelloWorld();
$o->sayHello();// Hello World!
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

2、多个trait

通过逗号分隔,在use声明列出多个trait,可以都插入到一个类中。

实例

<?php
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();//Hello
$o->sayWorld();//World
$o->sayExclamationMark();//!
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

3、冲突的解决

如果两个trait都插入了一个同名的方法,如果没有明确解决中途将会产生一个致命错误。

为了解决多个trait在通一个类中的命名冲突,需要使用insteadof操作符来明确指定使用冲突方法中的哪一个。

以上方式仅允许排除掉其它方法,as操作符可以为某个方法引入别名。注意,as操作符不会对方法进行重命名,也不会影响其方法。

实例

<?php
trait A{
    public function smallTalk(){
        echo "a";
    }

    public function bigTalk(){
        echo "A";
    }
}

trait B{
    public function smallTalk(){
        echo 'b';
    }

    public function bigTalk(){
        echo "B";
    }
}

class Talker{
    use A,B{
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
    }
}

class Aliased_Talker{
    use A,B{
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

4、修改方法的访问控制

使用as语法还可以用来调整方法的访问控制。

实例

<?php
trait HelloWorld{
    public function sayHello(){
        echo "Hello World!";
    }
}

//修改了sayhello的访问控制
class MyClass1{
    use HelloWorld{ sayHello as protected;}
}

// 给方法一个改变了访问控制的别名
// 原版 sayHello 的访问控制则没有发生变化

class MyClass2{
    use HelloWorld{ sayHello as private myPrivateHello;}
}
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

5、从trait来组成trait

实例

<?php
trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World!';
    }
}

trait HelloWorld {
    use Hello, World;
}

class MyHelloWorld {
    use HelloWorld;
}

$o = new MyHelloWorld();
$o->sayHello();
$o->sayWorld();
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

6、trait的抽象成员

实例

<?php
trait Hello {
    public function sayHelloWorld() {
        echo 'Hello'.$this->getWorld();
    }
    abstract public function getWorld();
}

class MyHelloWorld {
    private $world;
    use Hello;
    public function getWorld() {
        return $this->world;
    }
    public function setWorld($val) {
        $this->world = $val;
    }
}
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

7、trait的静态成员

实例

<?php
trait Counter {
    public function inc() {
        static $c = 0;
        $c = $c + 1;
        echo "$c\n";
    }
}

class C1 {
    use Counter;
}

class C2 {
    use Counter;
}

$o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

实例

<?php
trait Counter {
    public function inc() {
        static $c = 0;
        $c = $c + 1;
        echo "$c\n";
    }
}

class C1 {
    use Counter;
}

class C2 {
    use Counter;
}

$o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

实例

<?php
trait StaticExample {
    public static function doSomething() {
        return 'Doing something';
    }
}

class Example {
    use StaticExample;
}

Example::doSomething();
?>

运行实例 »

点击 "运行实例" 按钮查看在线实例

8、Trait 同样可以定义属性。

Trait 定义了一个属性后,类就不能定义同样名称的属性,否则会产生 fatal error。

五、final关键字

如果父类中的方法被声明为final,则子类无法覆盖该方法。如果一个类被声明为final,则不能继承。




Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post