如何在PHP类中使用已有的特征?

25

PHP(5.4)中是否有可以将使用的 traits 获取为数组或类似的函数:

class myClass extends movingThings {
  use bikes, tanks;

  __construct() {
    echo 'I\'m using the two traits:' . ????; // bikes, tanks
  }
}

1
我试图让你的问题更清晰。我认为你想从对象或类中获取自行车和坦克(你的特征)。类似于get_class_methods(),但是不存在get_class_traits() - Mike B
1
@Nik....,你为什么关闭它?在使用/review时,你不应该使用“关闭所有”的方法。 - tereško
7个回答

36

要轻松获取已使用的特性,您可以调用class_uses()

$usedTraits = class_uses(MyClass);
// or
$usedTraits = class_uses($myObject);

一般建议

在检查可用功能时,我通常建议使用接口。要向接口添加默认功能,您可以使用特性。这样,您还可以从类型提示中受益。

通过实现一个接口来强制对象具有功能,然后使用特性来实现该接口的默认代码。

class MyClass 
    implements SomeInterface 
{
    use SomeTrait;
}

然后你可以通过以下方式检查接口:

$myObject = new MyClass();
if ($myObject instanceof SomeInterface) {
    //...
}

仍然使用类型提示(type hinting);

function someFunction( SomeInterface $object )
{ 
    //...
}

12
您可以使用ReflectionClass自己编写代码。
$rc = new ReflectionClass('myClass');
$count = count($rc->getTraits());

getTraits()和class_uses是否相同?它返回类特征使用的特征名称吗?还是父类使用的特征? - Vladislav Rastrusny

8
< p>只是我的两分钱=)< /p>
in_array( "CLASS_NAME", class_uses($model) ) 

如果使用 PHP > 5.6 版本

in_array( CLASS_NAME::class, class_uses($model) )

2

class-uses(<class>)函数将获取<class>的直接traits,但它不会获取通过父类或traits of traits等方式继承的所有traits...

如果您需要完全获取类中继承的所有traits,我建议阅读官方文档中的注释:

http://php.net/manual/en/function.class-uses.php


@not_jagg_at_adecosystem 展示了这个限制的部分解决方案。 - Henry

2

class_usesReflectionClass->getTraits在获取子类的特性时无法正常工作。

例如:

trait A {}

class Mother {
    use A;
}

class Child extends Mother {}

var_dump(class_uses('Child'));  // empty array
var_dump(class_uses('Mother')); // has A

我遇到了这个问题,所以编写了简单的代码来获取所有类的特性。

function all_class_uses($model)
{
    $class = new ReflectionClass($model);
    $traits = $class->getTraits();
    while($parent = $class->getParentClass()) {
        $traits += $class->getTraits();
        $class = $parent;
    }
    return array_combine(array_keys($traits), array_keys($traits));
}

我认为在 while 循环中 $traits += $class->getTraits(); 应该改为 $traits += $parent->getTraits(); - Reinhold Füreder

1

I wish that will be useful (thanks to Maurice for interface usage):

    interface IHaveHasTrait
    {
        public function has_trait($name);
    };

    trait THaveHasTrait
    {
        public function has_trait($name)
        {
            $classes = class_parents( $this );
            $classes[] = get_class( $this );
            foreach( $classes as $class ) {
                foreach( class_uses( $class ) as $t ) {
                    if( $t === $name ) {
                        return true;
                    }
                }
            }
            return false;
        }
    };

    trait TLinkedListItem
    {
        use THaveHasTrait;
        public $next;
        public $prev;
    };

    class A implements IHaveHasTrait
    {
        use TLinkedListItem;
        public $text;

        public function __construct( $_text )
        {
            $this->text = $_text;
        }
    };

    class B extends A{};

    class C extends B{};

    class LinkedList
    {
        public function insertItem( &$item, $position=0, $relative=false )
        {
            if( is_a( $item, 'IHaveHasTrait' ) ) {
                echo $item->has_trait( 'TLinkedListItem' ) ? 'has' : 'not';
            }
        }
    };

    $a = new C('a');
    $l = new LinkedList;
    $l->insertItem($a);
    ?>


-2

简短回答:你不应该这样做。Traits 几乎是复制粘贴的代码。你不需要知道使用了哪些 traits,只需要知道 traits 生成了什么。

我不想给出的答案:使用 ReflectionClass::getTraits。我不会详细解释这个。


特质不仅仅是复制和粘贴。为什么不将特质信息用作某种元数据呢? - Ziumin
在我看来,特质几乎总是应该避免使用的,因为它只是一种紧密耦合代码的另一种方式。 - PeeHaa
@Levi Morrison,我并没有说你的答案是错误的。那么我的第二个问题呢? - Ziumin
Traits可以用作“复制和粘贴”的相反方式,以避免冗余代码。 - Teson
@LeviMorrison,我正在做一些很酷的事情,与反射无关。 - Teson
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接