![](/img/trans.png)
[英]Laravel conditionally load trait if class exists in package controller
[英]How can I conditionally make a class use a trait if it exists?
如果可用,我希望能夠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;
理想的情況是這樣的:
class foo
{
var $bar;
}
if (file_exists('myTrait.php')) {
include_once('myTrait.php');
//make class foo use myTrait;
}
$f=new foo();
很難找到文檔和特征似乎不是很受歡迎,但在我的特殊情況下,它們非常有用。 我還嘗試通過僅在需要時包含文件來盡可能降低資源。
像往常一樣歡迎提示、文檔和解釋。
我的搜索帶給我的最接近的是這篇文章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); } }
此特征現在提供具有通用數據庫功能的類。 任何需要數據庫連接的類,無論是控制器還是管理器(或任何東西),都可以使用這個特性:
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
interface BarInterface
{
/**
* @return string
*/
public function bar();
}
一個FooUsingBarTrait
類,它使用特征BarTrait
來實現上述接口:
<?php
class FooUsingBarTrait implements BarInterface
{
use BarTrait;
}
FooNotUsingBarTrait
類,它不使用特征BarTrait
,而是自己實現上述接口:
class FooNotUsingBarTrait implements BarInterface
{
public function bar()
{
return 'Hey, I am one of your friends!';
}
}
最后,根據特征BarTrait
是否存在,有條件地定義一個Foo
類:
<?php
if (trait_exists(BarTrait::class) {
class Foo extends FooUsingBarTrait
{
}
} else {
class Foo extends FooNotUsingBarTrait
{
}
}
$foo = new Foo();
$foo->bar();
var_dump(
get_class($foo),
class_parents(Foo::class)
);
注意如果兩個類FooUsingBarTrait
和FooNotUsingBarTrait
實現一個公共接口,這可能最有意義-畢竟,您可能想提供一些將在兩種實現之間共享的功能:一種使用特征,另一種通過其他方式(方法由該課)。
供參考,請參閱:
有關示例,請參見:
您的問題很有趣,並且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(),但是它解決了原本無法解決的問題時很有趣。
不管它有多糟糕,你都可以通過擴展類來實現。
trait AutoPilot {
function navigate() {
echo 'navigating...';
}
}
if (trait_exists('AutoPilot')) {
class Machine {
use AutoPilot;
}
} else {
class Machine {
}
}
class Car extends Machine {
}
$car = new Car;
$car->navigate();
這就是我最終得到的:
eval("class myClass {"
. (trait_exists('myTrait') ? "use myTrait;" : "")
. str_replace(['class ', '<?php'], '//', file_get_contents(myClass.php"))
);
總懶惰:
trait_exists
行以添加更多特征 class
關鍵字和<?php
標記,因此您不必編輯類文件 這對我和“按原樣”都很好,除了我粘貼此行的文件外,無需對任何文件進行任何修改。對您而言,情況可能並非如此。
考慮以下事實:
感謝lacalheinz的指導,但是Steven用eval()瞄准了靶心。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.