1.1.1. 07.类与对象2


1.抽象类

PHP 5 支持抽象类和抽象方法。定义为抽象的类不能被实例化。当一个类中有一个方法是抽象方法则,这个类就是抽象类

继承一个抽象类后,子类必须实现抽象类中所有抽象方法。

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

此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。

<?php
  abstract class AbstractClass {
    abstract public function test();
  }

  class Son extends AbstractClass{
    public function test(){
      echo "test";
    }
  }

2.对象接口

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

使用接口(interface)定义的类,和定义一个标准类一样,不过所有的方法都必须是空的。(不可定义属性)

接口的所有方法都必须是公有的。

使用 implements 关键字来实现一个接口。可以一次性实现多个接口。实现多个接口时,方法不能重名。

接口可以继承,使用 extends 关键字。

类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误。

<?php
    interface a{
        public function foo1();
    }

    interface b extends a{
        public function foo2();
    }

    interface c {
        public function foo3();
    }

    class demo implements b,c {

        public function foo1(){
            echo 'foo1'.PHP_EOL;
        }
        public function foo2(){
            echo 'foo2'.PHP_EOL;
        }
        public function foo3(){
            echo 'foo3'.PHP_EOL;
        }
    }

    $obj = new demo();
    $obj->foo1();
    $obj->foo2();
    $obj->foo3();

3.trait

自 PHP 5.4.0 起,PHP 实现了一种代码复用的方法,称为 trait。

trait 可以让单继承的语言准备进行代码复用,避免传统多继承带来的问题。

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

    class world{
        use hello;

        public function sayHelloWorld(){
            $this->sayHello();
            echo 'World';
        }
    }

    $obj = new world();
    $obj->sayHelloWorld(); // Hello World

从基类继承的成员会被 trait 插入的成员所覆盖。优先顺序是来自当前类的成员覆盖了 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();
?>

多个 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();
        $o->sayWorld();
        $o->sayExclamationMark();
?>

如果多个trait中。都有同名的方法,则会产生冲突,冲突会产生一个致命的错误。

可以使用 insteadof 来指明当产生冲突时,使用哪一个。

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;
            B::bigTalk as talk;
        }
    }

    $obj = new Talker();
    $obj->smallTalk(); // b
    $obj->bigTalk(); // A
    $obj->talk(); // B

使用 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;
            B::bigTalk as talk;
            smallTalk as protected; // 改变方法的访问控制
        }
    }

    $obj = new Talker();
    $obj->smallTalk(); // 报错
    $obj->bigTalk();
    $obj->talk();

使用 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;
    }

    $obj = new MyHelloWorld();
    $obj->sayHello();
    $obj->sayWorld();

trait 的抽象方法、静态成员、属性

<?php
    trait Hello {
        private $hello = 'Hello ';
        abstract public function sayHello();
    }

    trait World {
        public static $world='World';
        public static function sayWorld() {
            echo self::$world;
        }
    }

    trait HelloWorld {
        use Hello,World;
        public function sayHello(){
            echo $this->hello;
        }
    }

    class MyHelloWorld{
        use HelloWorld;
    }

    $obj = new MyHelloWorld();
    $obj->sayHello();
    $obj->sayWorld();

4.匿名类

php 7 之后支持匿名类,匿名类很有用,可以创建一次性的简单对象。

    $a = new class{
        public function say(){
            echo 'Hello';
        }
    };
    $a->say(); // Hello

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

    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()
                {
                    return $this->prop2 + $this->prop3 + $this->func1(); // 2+1+3
                }
            };
        }
    }

    echo (new Outer)->func2()->func3(); // 6
Copyright © Kagami丶 2019 all right reserved,powered by Gitbook该文件修订时间: 2019-10-18 01:06:22

results matching ""

    No results matching ""