Php 如果存在一个trait,我如何有条件地让类使用它?

Php 如果存在一个trait,我如何有条件地让类使用它?,php,traits,Php,Traits,我希望能够使用特性(如果可用) 显然,我不能在类本身内部定义它(语法错误) 理想情况是这样的: class foo { var $bar; } if (file_exists('myTrait.php')) { include_once('myTrait.php'); //make class foo use myTrait; } $f=new foo(); 很难找到文档和特性似乎并不流行,但在我的特殊情况下,它们非常有用。我还试图通过仅在需要时包含文件来尽可能地减少资

我希望能够
使用
特性(如果可用)

显然,我不能在类本身内部定义它(语法错误)

理想情况是这样的:

class foo
{
    var $bar;
}

if (file_exists('myTrait.php')) {
   include_once('myTrait.php');
   //make class foo use myTrait;
}

$f=new foo();
很难找到文档和特性似乎并不流行,但在我的特殊情况下,它们非常有用。我还试图通过仅在需要时包含文件来尽可能地减少资源

如往常一样,欢迎提供提示、文档和解释


我的搜索给我带来的最接近的东西是这篇文章

假设其中一些控制器(但不是全部)需要 数据库连接。为了保持业绩,我们不应该放弃每一个机会 控制数据库连接。我们能做的就是写一个 扩展提供数据库的BaseController的抽象类 连接。但是,在未来,如果一个不是 控制器需要数据库连接吗?而不是复制这个 在逻辑上,我们可以使用水平重用

可以创建一个简单的特征:

trait DatabaseAware 
{    
    protected $db;

    public function setDatabase($db) 
    {
        $this->db = $db;
    }

    protected function query($query) 
    {
        $this->db->query($query);
    }
}
这个特性现在为类提供了通用的数据库功能。 任何需要数据库连接的类,无论是控制器还是 管理者(或任何人)可以使用以下特征:

class IndexController extends BaseController 
{
    use DatabaseAware;

    public function indexAction() 
    {
        $this->query("SELECT * FROM `someTable`");
    }
}
当我根据不同对象的需求实现特征时。数据库连接、调试报告等。

简单

特质 一个特性可能可用或不可用,将被使用或不使用,但最终将有助于实现接口:

<?php

trait BarTrait
{
    public function bar()
    {
        return 'Hey, I am your friend!';
    }
}
<?php

class FooUsingBarTrait implements BarInterface
{
    use BarTrait;
}
类不使用trait 一个类
footusingbartrait
,它不使用trait
BarTrait
,而是实现上述接口本身:

class FooNotUsingBarTrait implements BarInterface
{
    public function bar()
    {
        return 'Hey, I am one of your friends!';
    }
}
有条件地创建类定义 最后,根据trait
BarTrait
是否存在,有条件地定义一个类
Foo

<?php

if (trait_exists(BarTrait::class) {
    class Foo extends FooUsingBarTrait
    {
    }
} else {
    class Foo extends FooNotUsingBarTrait
    {
    }
}
注意如果两个类
fooousingbartrait
fooonotusingbartrait
都实现了一个公共接口,那么这可能是最有意义的——毕竟,您可能希望提供一些在两个实现之间共享的功能:一个使用特征,另一个通过其他方式(该类提供的方法)

有关参考,请参阅:

有关示例,请参见:


您的问题很有趣,eval()很可能满足您的需要。这种使用代码生成的方式很难看,但我知道它是有效的,因为我自己在自己的机器上验证了它。下面是您的方法:

$src = '
class foo {
  var $bar; // and all of your other code goes here
';
if (file_exists('myTrait.php')) {
  include_once('myTrait.php');
  $src .= "use myTrait;\n";
}
$src .= "}";
eval ($src); // your class finally gets declared

我不经常使用eval(),但当它解决了一个传统方法无法解决的问题时,它会很有趣。

以下是我的结论:

eval("class myClass {" 
    . (trait_exists('myTrait') ? "use myTrait;" : "") 
    . str_replace(['class ', '<?php'], '//', file_get_contents(myClass.php"))
);
eval(“类myClass{”
(trait_存在('myTrait')?“使用myTrait;”:“”)

.str_replace(['class','您可以根据trait的存在定义一个完整的类(如果trait_存在('myTrait'))
)一个
trait
“增强”一个有新方法的类。如果你不知道在什么时候编写代码时类是否提供了这些方法,你打算如何使用这些方法?在我看来,你试图以错误的方式解决一个完全不同的问题。“我还试图通过只在需要时包含文件来尽可能减少资源。”--这是自动加载程序的责任。@axiac这可以通过实现接口来解决-要么trait提供了实现,要么就实现了。trait不是动态功能。它要么存在,要么就不存在。如果它不存在,那么
使用的类也不存在;它们无法加载如果特征存在,那么整个问题就没有任何意义。在你需要的地方使用它,不要费心检查它的存在。如果你需要一个可能可用或不可用的功能(因为外部原因,而不是因为代码不存在)然后,解决方案使用了其他技术:和设计模式。很多文档都谈到了与traits一起使用的界面。我将在界面文档中挖掘更多内容。你的大部分答案都是我已经知道但从另一个角度来看的。呵呵,很高兴为你服务-希望解决方案对你有效,@LouisLoudogTrottier!我猜是这样的$src可以是任何解释为字符串的东西?
ob_start();包括'src/class.php';$src=ob_get_contents();…
我的问题可能很有趣,但我会更有趣地尝试这个问题,并调整它以适应我的懒散。这没什么大不了的,但我肯定会尝试一下,因为这似乎是最接近我所寻找的解决方案。谢谢你,有点吹毛求疵,我能够将其混合到一行中。而且,现在真正的乐趣开始了,我知道如何利用它以及何时不使用它。我很高兴它对你有用!看起来你在我建议的答案上有所改进。根据你的评论,我很确定我知道你做了什么,我认为这很好!
$foo = new Foo();

$foo->bar();

var_dump(
    get_class($foo),
    class_parents(Foo::class)
);
$src = '
class foo {
  var $bar; // and all of your other code goes here
';
if (file_exists('myTrait.php')) {
  include_once('myTrait.php');
  $src .= "use myTrait;\n";
}
$src .= "}";
eval ($src); // your class finally gets declared
eval("class myClass {" 
    . (trait_exists('myTrait') ? "use myTrait;" : "") 
    . str_replace(['class ', '<?php'], '//', file_get_contents(myClass.php"))
);