编程

PHP 没有多继承的原因

651 2024-03-20 09:23:00

多年来,PHP 作为一种语言已经有了很大的发展。从最初由 Rasmus Lerdorf 作为他的业余项目开始的一种简单的函数式脚本语言,到支持面向对象编程功能 PHP,已经走过了漫长的道路。

尽管 PHP 在其每一个版本中都在实现和改进面向对象编程的功能,但有一个功能是缺失的,我一直想知道为什么这些年来 PHP 中没有这个功能,即多继承。

PHP 不支持多继承有一个非常合理的原因。要了解这一点,我们需要深入了解这一概念的根源。多重继承实际上受到钻石问题的影响。

“钻石问题”(有时被称为“致命的死亡钻石”)指是当两个类 B 和 C 从 A 继承,而类 D 从 B 和 C 继承时产生的歧义。如果 A 中有一个方法 B 和 C 已经重写,而 D 没有重写它,那么 D 继承了该方法的哪个版本:B 的还是 C 的?

假设 PHP 支持多重继承,以此为例:

Diamond Problem in inheritance

假设 SuperClass 是一个声明了一些方法的抽象类,而 ClassA ClassB 是具体类。

<?php

class SuperClass
{
    protected function greet()
    {
        echo "Grandparent";
    }
}

// First Parent class
class ClassA extends SuperClass
{
    protected function greet()
    {
        echo "Parent1";
    }
}
 
// Second Parent class
class ClassB extends SuperClass
{
    protected function greet()
    {
        echo "Parent2";
    }
}
 
class ClassC extends ClassA, ClassB
{
    public function test()
    {
        $c = new self();
        $c->greet();
    }
}

如上所示,在 ClassC 中调用 greet() 方法,编译器不可能知道应该调用 ClassA 的 greet() 还是 ClassB 的 greet() 方法。因此,为了避免这样的并发症,PHP 不支持多继承。

PHP 中钻石问题的缓解

解决 PHP 中没有多重继承的一个方案是使用 trait。Trait 是一种在单继承语言(如 PHP)中重用代码的机制,通过这种方式可以对其使用多重继承。基本上,trait 就像类,除了不能初始化 trait 实例。这就像直接在类中使用类成员,而不需要实例化或继承它们。

下面是一个例子,说明如何定义一个 trait 并在类中使用它

trait myTrait 
{
    public function whereAmI()
    {
        echo __CLASS__;
    }
}

class Hello
{
    use myTrait;
}

$a = new Hello;
$a->whereAmI(); //Hello

类似地,你可以在一个类中使用多个 trait,使用逗号作为分隔符。

use Hello, World;

另一个解决方案是在设计软件时使用组合。基本上,组合是一种通过包含实现所需功能的其他类的实例来跨类重用代码的机制。查看以下示例。

<?php
class Vehicle
{    
    public function move()
    {
        echo "Move the car";
    }    
}

class Car
{
    private $vehicle;

    public function __construct(Vehicle $vehicle)
    {
        $this->vehicle = $vehicle;
    }

    public function accelarate()
    {    
        $this->vehicle->move();    
    }
}

如上,我们通过构造函数在 Car 类中注入了 Vehicle 类,通过这种方式,我们可以在 Car 类中访问 Vehicle 类的成员。如果你像使用 Car 类中使用另一个类 Tyre,你只需在构造函数中注入其实例,如下。

<?php
class Vehicle
{    
    public function move()
    {
        echo "Move the car";
    }    
}

class Tire
{    
    public function addAlloys()
    {
        echo "Adding alloy wheels...";
    }    
}

class Car
{
    private $vehicle;

    private $tire;

    public function __construct(Vehicle $vehicle, Tire $tire)
    {
        $this->vehicle = $vehicle;
        $this->tire = $tire;
    }

    public function accelarate()
    {    
        $this->vehicle->move();    
        $this->tire->addAlloys();
    }
}

这种方式在面向对象编程中被称为“组合优于继承”,可查看此文:http://tubring.cn/articles/reasons-use-composition-over-inheritance-php