【发布时间】:2016-03-22 20:33:18
【问题描述】:
我目前正在开发一个 trait 自动初始化器,它的一切工作都很好而且很漂亮,但遗憾的是,trait 有一些严重的限制。
我遇到的一个问题如下:
trait constructor{}
trait cache{}
trait database{}
trait settings{} # requires database or cache.
现在,为了让我的自动加载系统正常工作,我必须以正确的顺序定义使用,如下所示:
class t{
use constructor, cache, settings;
}
如果我会这样做:
class t{
use constructor, settings, cache;
}
设置特征初始化器将在缓存初始化器之前调用,因此缓存特征内的$cache 变量为空。
现在一个简单的解决方案是将use cache, database; 添加到设置特征中,但是如果被另一个必须包含的特征使用,这可能会导致定义的方法发生冲突。
另一种解决方案是检查属性$cache 是否已定义,然后检查它是否已设置,但这会产生大量冗余代码,我不想为每个特征编写。
现在代码的逻辑如下:
trait constructor{
function init(){
echo 'I am called first';
print_r(class_uses(self::class))/*[
'constructor' => 'constructor',
'cache' => 'cache',
'database' => 'database',
'settings' => 'settings'
// Sorted in sequence as defined in the class.
]*/
# now call other trait initializers.
}
}
trait settings{
function settings(){
echo 'I am called last, but before __construct()';
}
}
class t{
use constructor; // required by all traits
use cache; // requires constructor.
use database; // requires constructor.
use settings; // requires constructor, cache || database.
function __construct(){
echo 'I am called after init()';
$this->db->prepare(...)->execute();
}
}
可以在构造函数中对数组进行排序,以确保设置在缓存或数据库之后被索引。然而,棘手的部分来了,最好的方法是什么?
由于大多数类只使用少量特征,定义一个冗长的数组作为排序的基础似乎是不够的。由于该系统在 CMS 的核心运行,我宁愿按特征排序。
trait 的问题是我不能在课堂上定义相同的东西两次,所以我想将范围污染保持在最低限度。
【问题讨论】:
-
有趣。我们一直在遇到特性(和/或加载它们的客户端类)的依赖问题,并决定避免使用它们,而是使用我们可以依赖注入的适当类。然而,在某些情况下,这与其说是一个好的解决方案不如说是一个坏事。只是想知道,您的目标是哪个 PHP 版本?我问是因为 5.4 和 5.6 之间有一些变化,也可能在 5 和 7 之间。
-
我目前正在专门为 PHP 7 进行重写,但是用于实现这一奇迹的代码与 5.4 非常兼容。