Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 特征依赖顺序加载_Php_Sorting_Oop_Traits - Fatal编程技术网

Php 特征依赖顺序加载

Php 特征依赖顺序加载,php,sorting,oop,traits,Php,Sorting,Oop,Traits,我目前正在研究一个特征自动初始化器,它工作得很好,但是不幸的是,在特征上有一些严重的限制 我遇到的一个问题是: trait constructor{} trait cache{} trait database{} trait settings{} # requires database or cache. class t{ use constructor, settings, cache; } trait constructor{ function init(){ echo

我目前正在研究一个特征自动初始化器,它工作得很好,但是不幸的是,在特征上有一些严重的限制

我遇到的一个问题是:

trait constructor{}
trait cache{}
trait database{}
trait settings{} # requires database or cache.
class t{
  use constructor, settings, 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();
  }
}
现在,为了让我的自动加载系统工作,我必须按照正确的顺序定义使用,如下所示:

class t{
  use constructor, cache, settings;
}
如果我能做到以下几点:

trait constructor{}
trait cache{}
trait database{}
trait settings{} # requires database or cache.
class t{
  use constructor, settings, 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();
  }
}
将在缓存初始值设定项之前调用settings trait初始值设定项,因此缓存trait中的
$cache
变量为null

现在一个简单的解决方案是添加
使用缓存、数据库
另一个解决方案是检查属性
$cache
是否已定义,然后检查是否已设置,但这将创建大量冗余代码,我不希望为每个特性编写这些代码

现在,代码的逻辑如下所示:

trait constructor{}
trait cache{}
trait database{}
trait settings{} # requires database or cache.
class t{
  use constructor, settings, 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的核心运行的,所以我宁愿按照一个特征一个特征地排序


traits的问题是,我不能两次定义同一件事,也不能在类中定义,因此我希望将范围污染降至最低。

我找到了一个可行的解决方案,没有太多冗余代码

trait constructor{
  private $traits;

  function loaded(array $list){
    foreach($list as $trait){
      if(isset($this->_traits[$trait])){ // class_uses returns array of ['trait' => 'trait'] while I append numeric.
        $this->_traits[] = $this->_current; // append the current looping method (of init) to be loaded last.
        return false;
      }
    }
    return true;
  }

  function init(){
    $traits = class_uses(self::class);
    while(list(,$method) = each($this->traits)){
      unset($this->_traits[$method]); // avoid infinite loop.
      // This while loop will loop trough newly added values added by 'loaded' 
      call_user_func([$this, $method]);
    }
  }
}

trait settings{
  function settings(){
    if($this->loaded(['cache', 'database'])){
      # This method will queue the 'settings' method for later regardless if the traits are already loaded.
      # So it will first load the traits that don't have dependency's.
      # The order is not important because the __construct method is called last anyways.
    }
  }
}

如果有人有任何其他建议,只需添加一个答案。

有趣。我们在traits(和/或加载它们的客户机类)方面一直存在依赖性问题,并决定不使用它们,而是使用我们可以依赖性注入的适当类。然而,在某些情况下,这与其说是一个好的解决方案,不如说是一个较小的罪恶。只是想知道,你的目标是哪个PHP版本?我这样问是因为在5.4和5.6之间以及5和7之间有一些变化。我目前正在专门为PHP7重写,但是用于实现这一神奇的代码与5.4非常兼容。