什么是 parent:: trait 的作用域

What is parent:: scope for a trait

我有一个使用特征 MyTrait 的 class MyClass。它们都有一个方法 getName()(MyClass 继承自 MyParentClass)。

MyTrait::getName() 的父作用域是什么?在 MyTrait 上下文中调用 MyClass::getName() 和 MyParentClass::getName() 的正确方法是什么?

参考下面的代码。

trait MyTrait {
   public function getName() : string
   { 
       return parent::getName() . '_special';
   }
}

class MyParentClass {
   public function getName(): string
   {
      return "MyName";
   }
}
class MyClass extends MyParentClass {
   use MyTrait;

}

特征方法的行为就像它们在 class 中使用特征声明,即

trait MyTrait {
   public function getName() : string
   {
       return parent::getName() . '_special';
   }
}

class MyClass extends MyParentClass {
   use MyTrait;

}

在功能上与

相同
class MyClass extends MyParentClass {
   public function getName() : string
   {
       return parent::getName() . '_special';
   }
}

应该清楚,在这种情况下parent指的是MyParentClass。如果有任何疑问,请使用以下代码:

<?php

trait MyTrait {
   public function getName() : string
   {
       return parent::getName() . '_special';
   }
}

class MyParentClass {
   public function getName(): string
   {
      return "MyName";
   }
}
class MyClass extends MyParentClass {
   use MyTrait;

}

$instance = new MyClass();

echo $instance->getName();

产生以下输出:

MyName_special

这可以进一步 tested/demonstrated 在 trait 方法中使用 return parent::class; (ref),其中 returns MyParentClass.

您需要在子类中定义一个 getName() 方法。根据 manual,traits 的先例是:

An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.

这意味着因为您的子类中没有 getName() 方法,所以 trait 方法优先,覆盖父方法。在子类中有一个getName()方法,它优先。

因此您需要执行以下操作,请注意特征用法中 getName() 方法的别名:

trait MyTrait {
    public function getName() : string
    {
        return parent::getName() . '_special';
    }
}

class MyParentClass {
    public function getName(): string
    {
        return "MyName";
    }
}
class MyClass extends MyParentClass {
    use MyTrait {
        MyTrait::getName as getTraitName;
    }

    public function getName(): string
    {
        return parent::getName();
    }
}

$myClass = new MyClass();
var_dump($myClass->getName()); //string(6) "MyName"
var_dump($myClass->getTraitName()); //string(14) "MyName_special"