Skip to content

抽象类 ​

从具体事物抽出、概括出它们共同的方面、本质属性与关系等,而将个别的、非本质的方面、属性与关系舍弃,这种思维过程,称为抽象。

php中如果一个类的方法被定义为抽象,那么该类就是抽象类。抽象类不能被实例化。只能被子类继承,子类必须实现全部的抽象方法,并且访问修饰必须和父类相同或者更宽松。参数必须一致。

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

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

对象接口 ​

接口泛指实体把自己提供给外界的一种[抽象化](可以为另一实体),用以由内部操作分离出外部沟通方法,使其能被内部修改而不影响外界其他实体与其交互的方式。

使用接口不需要实现哪些方法,只需要定义这些方法。具体的实现由类去实现。

接口通过interface定义。实现接口通过implements。接口可以被继承

接口中也可以定义常量。但是不能定义属性。接口允许多继承

php
interface Iter{
  public function test();
}

class ClassT implements Iter{
  public function test(){
    
  }
}
interface Iter2 extends Iter {
  public function test2();
}

class ClassT2 implements Iter2 {
  public function test(){}
  public function test2(){}
}

#多继承
interface Iter3 extends Iter1,Iter2{}

/**
* An example of duck typing in PHP
*/

interface CanFly {
  public function fly();
}

interface CanSwim {
  public function swim();
}

class Bird {
  public function info() {
    echo "I am a {$this->name}\n";
    echo "I am an bird\n";
  }
}

/**
* some implementations of birds
*/
class Dove extends Bird implements CanFly {
  var $name = "Dove";
  public function fly() {
    echo "I fly\n";
  } 
}

class Penguin extends Bird implements CanSwim {
  var $name = "Penguin";
  public function swim() {
    echo "I swim\n";
  } 
}

class Duck extends Bird implements CanFly, CanSwim {
  var $name = "Duck";
  public function fly() {
    echo "I fly\n";
  }
  public function swim() {
    echo "I swim\n";
  }
}

/**
* a simple function to describe a bird
*/
function describe($bird) {
  if ($bird instanceof Bird) {
    $bird->info();
    if ($bird instanceof CanFly) {
      $bird->fly();
    }
    if ($bird instanceof CanSwim) {
      $bird->swim();
    }
  } else {
    die("This is not a bird. I cannot describe it.");
  }
}

// describe these birds please
describe(new Penguin);
echo "---\n";

describe(new Dove);
echo "---\n";

describe(new Duck);

Trait ​

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制.无法通过 trait 自身来实例化。它为传统继承增加了水平特性的组合

trait定义 ​

php
trait t{
  public function test(){}
}
# 使用
class Test{
  use t;
  public function test2{
    $this->test();
  }
}

优先级 ​

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

php
class Base {
	public function say(){
		echo "base";
	}
}
trait Test{
	public function say(){
		echo "trait";
	}
}

class Son extends Base {
	use Test;
	public function test(){
		$this->say();
	}
}

$s = new Son();
$s->test();//trait
# 在子类中重写say。则调用子类的say方法 
public function say(){
		echo "son";
}

多个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 '!';
    }
}

冲突的解决 ​

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

为了解决多个 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;
    }
}

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

使用as修改访问控制 ​

php
class Base {
	public function say(){
		echo "base";
	}
}
trait Test{
	public function say(){
		echo "trait";
	}
}

class Son extends Base {
	use Test {say as private say2;}
	public function say(){
		echo "son";
	}
}

$s = new Son();
$s->say2();//error

使用多个trait组合 ​

php
trait A{}
trait B{}
trait C{use A,B;}

trait抽象成员方法 ​

为了对使用的类施加强制要求,trait 支持抽象方法的使用

php
trait T{
  abstract public function test();
}

class Test{
  use T;
  public function test(){}
}

trait 静态方法 ​

php
trait T{
   public static function test() {};
}

class Test{
  use T;
}
Test::test();

trait定义属性 ​

Trait 定义了一个属性后,类就不能定义同样名称的属性

php
trait PropertiesTrait {
    public $same = true;
    public $different = false;
}

class PropertiesExample {
    use PropertiesTrait;
    public $same = true; // PHP 7.0.0 后没问题,之前版本是 E_STRICT 提醒
    public $different = true; // 致命错误

匿名类 ​

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

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

php
$a = new class {
  public function test(){
    echo "test";
  }
};
$a->test();

基于 VitePress 构建 · 欢迎 Star 与 PR