我怎样才能有条件地让 class 使用一个特征(如果它存在)?
How can I conditionally make a class use a trait if it exists?
我希望能够 use
特性 如果它可用。
显然我无法在 class 本身内部定义它(语法错误)
//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/
Let's say a few of these controllers (but not all of them) require a
database connection. To keep performance up, we shouldn't give every
controller the database connection. What we could do is write an
abstract class which extends BaseController which provides a database
connection. But, in the future, what if an object that is not a
controller requires a database connection? Instead of duplicating this
logic, we can use horizontal reuse.
A simple trait can be created:
trait DatabaseAware
{
protected $db;
public function setDatabase($db)
{
$this->db = $db;
}
protected function query($query)
{
$this->db->query($query);
}
}
This trait now provides classes with common database functionality.
Any class which requires a database connection, be it a controller or
a manager (or anything), can use this trait:
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();
}
Class 使用特征
A class FooUsingBarTrait
使用特征 BarTrait
来实现上述接口:
<?php
class FooUsingBarTrait implements BarInterface
{
use BarTrait;
}
Class 没有使用 trait
A class FooNotUsingBarTrait
不使用特征 BarTrait
,而是实现上述接口本身:
class FooNotUsingBarTrait implements BarInterface
{
public function bar()
{
return 'Hey, I am one of your friends!';
}
}
有条件地创建 class 定义
最后,有条件地定义一个classFoo
,取决于一个traitBarTrait
是否存在:
<?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)
);
注意 如果 classes FooUsingBarTrait
和 FooNotUsingBarTrait
都实现一个公共接口,这可能最有意义 - 毕竟,你可能想要提供一些将在两个实现之间共享的功能:一个使用特征,另一个通过其他方式(由 class 提供的方法)。
参考:
- http://php.net/manual/en/function.class-parents.php
- http://php.net/manual/en/function.trait-exists.php
示例见:
您的问题很有趣,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"))
);
完全懒惰:
- 重复
trait_exists
行以添加更多特征
- 注释掉
class
关键字和 <?php
标签,这样您就不必编辑 class 文件
- 评估一长行臭代码。
这对我和和'as is'来说很好用,除了我粘贴这一行的文件之外,没有对任何文件进行任何修改。它可能不会是适合你的案例。
考虑以下事实:
- 不要使用结束 php 标签
- 只有一个 class 文件
- 您需要添加任何其他关键字(扩展、实施...)
- 根据您的代码,可能还有更多意想不到的行为
感谢 lacalheinz 的指导post 但史蒂文用 eval() 瞄准了靶心。
无论多糟糕,你都可以通过扩展 class.
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();
我希望能够 use
特性 如果它可用。
显然我无法在 class 本身内部定义它(语法错误)
//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/
Let's say a few of these controllers (but not all of them) require a database connection. To keep performance up, we shouldn't give every controller the database connection. What we could do is write an abstract class which extends BaseController which provides a database connection. But, in the future, what if an object that is not a controller requires a database connection? Instead of duplicating this logic, we can use horizontal reuse.
A simple trait can be created:
trait DatabaseAware { protected $db; public function setDatabase($db) { $this->db = $db; } protected function query($query) { $this->db->query($query); } }
This trait now provides classes with common database functionality. Any class which requires a database connection, be it a controller or a manager (or anything), can use this trait:
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();
}
Class 使用特征
A class FooUsingBarTrait
使用特征 BarTrait
来实现上述接口:
<?php
class FooUsingBarTrait implements BarInterface
{
use BarTrait;
}
Class 没有使用 trait
A class FooNotUsingBarTrait
不使用特征 BarTrait
,而是实现上述接口本身:
class FooNotUsingBarTrait implements BarInterface
{
public function bar()
{
return 'Hey, I am one of your friends!';
}
}
有条件地创建 class 定义
最后,有条件地定义一个classFoo
,取决于一个traitBarTrait
是否存在:
<?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)
);
注意 如果 classes FooUsingBarTrait
和 FooNotUsingBarTrait
都实现一个公共接口,这可能最有意义 - 毕竟,你可能想要提供一些将在两个实现之间共享的功能:一个使用特征,另一个通过其他方式(由 class 提供的方法)。
参考:
- http://php.net/manual/en/function.class-parents.php
- http://php.net/manual/en/function.trait-exists.php
示例见:
您的问题很有趣,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"))
);
完全懒惰:
- 重复
trait_exists
行以添加更多特征 - 注释掉
class
关键字和<?php
标签,这样您就不必编辑 class 文件 - 评估一长行臭代码。
这对我和和'as is'来说很好用,除了我粘贴这一行的文件之外,没有对任何文件进行任何修改。它可能不会是适合你的案例。
考虑以下事实:
- 不要使用结束 php 标签
- 只有一个 class 文件
- 您需要添加任何其他关键字(扩展、实施...)
- 根据您的代码,可能还有更多意想不到的行为
感谢 lacalheinz 的指导post 但史蒂文用 eval() 瞄准了靶心。
无论多糟糕,你都可以通过扩展 class.
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();