douza9835 2016-03-22 20:33
浏览 32
已采纳

特征依赖性依次加载

I'm currently working on a trait auto initializer and its all working fine and dandy however there are sadly some severe limitations on traits.

One issue I came across is the following:

trait constructor{}
trait cache{}
trait database{}
trait settings{} # requires database or cache.

Now for my auto loading system to work I must define the use in the correct sequence like so:

class t{
  use constructor, cache, settings;
}

If I would do the following:

class t{
  use constructor, settings, cache;
}

The settings trait initializer will be called before the cache initializer and thus the $cache variable inside the cache trait is null.

Now a simple solution would be to add use cache, database; to the settings trait however that can result in collisions of defined methods if used by another trait that must be included.

Another solution would be to check if the property $cache is defined and then check if it's set but this would create a lot of redundant code I'd rather not want to write for each and every trait.

Now the logic of the code is the following:

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();
  }
}

It is in the constructor possible to sort the array to make sure the settings is indexed after cache or database. However here comes the tricky part, what is the best approach to do this?

Since most classes only use a small number of traits, defining a lengthy array to use as a base for sorting seems deficient. As this system is running at the core of the CMS I'd rather sort on a trait by trait basis.

The problem with traits is that I cannot define the same thing twice, noor in class as well so I'd like to keep the scope pollution to a minimum.

  • 写回答

1条回答 默认 最新

  • douzi9211 2016-03-27 13:23
    关注

    I've found a viable solution to the issue without too much redundant code.

    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.
        }
      }
    }
    

    If anyone has any other suggestion, just add an answer.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab
  • ¥20 重新写的代码替换了之后运行hbuliderx就这样了
  • ¥100 监控抖音用户作品更新可以微信公众号提醒
  • ¥15 UE5 如何可以不渲染HDRIBackdrop背景
  • ¥70 2048小游戏毕设项目
  • ¥20 mysql架构,按照姓名分表
  • ¥15 MATLAB实现区间[a,b]上的Gauss-Legendre积分
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 linux驱动,linux应用,多线程