如果存在,如何有条件地使类使用特征?

Lou*_*ier 2 php traits

如果可用,我希望能够使用use该特性。

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

//fails
include_once('myTrait.php');

class foo
{ 
    var $bar; 

    if (trait_exists('myTrait')) {
        use myTrait;
    }
}

//also fails
foo use myTrait;

//also fails
$f = new foo();
$f use myTrait;

//also fails
$f = new foo() use myTrait;
Run Code Online (Sandbox Code Playgroud)

理想的情况是这样的:

class foo
{
    var $bar;
}

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

$f=new foo();
Run Code Online (Sandbox Code Playgroud)

很难找到文档和特征似乎不是很受欢迎,但在我的特殊情况下,它们非常有用。我还尝试通过仅在需要时包含文件来尽可能降低资源。

像往常一样欢迎提示、文档和解释。


我的搜索带给我的最接近的是这篇文章http://brendan-bates.com/traits-the-right-way/

假设其中一些控制器(但不是全部)需要数据库连接。为了保持性能,我们不应该为每个控制器提供数据库连接。我们可以做的是编写一个抽象类,它扩展了提供数据库连接的 BaseController。但是,将来,如果不是控制器的对象需要数据库连接怎么办?我们可以使用水平重用,而不是复制这个逻辑。

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

trait DatabaseAware 
{    
    protected $db;

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

    protected function query($query) 
    {
        $this->db->query($query);
    }
}
Run Code Online (Sandbox Code Playgroud)

此特征现在提供具有通用数据库功能的类。任何需要数据库连接的类,无论是控制器还是管理器(或任何东西),都可以使用这个特性:

class IndexController extends BaseController 
{
    use DatabaseAware;

    public function indexAction() 
    {
        $this->query("SELECT * FROM `someTable`");
    }
}
Run Code Online (Sandbox Code Playgroud)

当我根据不同对象的需要实现特征时。数据库连接、调试报告等。

loc*_*inz 5

简单!

特征

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

<?php

trait BarTrait
{
    public function bar()
    {
        return 'Hey, I am your friend!';
    }
}
Run Code Online (Sandbox Code Playgroud)

界面

我们希望实现的接口:

<?php

interface BarInterface
{
    /**
     * @return string
     */
    public function bar();
}
Run Code Online (Sandbox Code Playgroud)

使用 trait 类

一个FooUsingBarTrait使用 traitBarTrait来实现上述接口的类:

<?php

class FooUsingBarTrait implements BarInterface
{
    use BarTrait;
}
Run Code Online (Sandbox Code Playgroud)

不使用 trait 的类

一个FooNotUsingBarTrait不使用 trait BarTrait,而是实现上述接口本身的类:

class FooNotUsingBarTrait implements BarInterface
{
    public function bar()
    {
        return 'Hey, I am one of your friends!';
    }
}
Run Code Online (Sandbox Code Playgroud)

有条件地创建类定义

最后,Foo根据特征是否BarTrait存在,有条件地定义一个类:

<?php

if (trait_exists(BarTrait::class) {
    class Foo extends FooUsingBarTrait
    {
    }
} else {
    class Foo extends FooNotUsingBarTrait
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

创建您的实例

$foo = new Foo();

$foo->bar();

var_dump(
    get_class($foo),
    class_parents(Foo::class)
);
Run Code Online (Sandbox Code Playgroud)

注意这可能更有意义,如果两个类FooUsingBarTraitFooNotUsingBarTrait实现共同的接口-毕竟,你可能想提供一些功能,这将在两个实现之间可以共享:使用特点,通过该类提供的其他方式(方法中的一种,其他)。

参考:

有关示例,请参阅:


Ste*_*ven 1

你的问题很有趣,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
Run Code Online (Sandbox Code Playgroud)

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