1 <?php
  2 
  3 /**
  4  * Instance Pool Trait.
  5  *
  6  * @author gharlan
  7  *
  8  * @package redaxo\core
  9  */
 10 trait rex_instance_pool_trait
 11 {
 12     /**
 13      * @var static[][]
 14      */
 15     private static $instances = [];
 16 
 17     /**
 18      * Constructor.
 19      */
 20     private function __construct()
 21     {
 22         // noop
 23     }
 24 
 25     /**
 26      * Adds an instance.
 27      *
 28      * @param mixed $key      Key
 29      * @param self  $instance Instance
 30      */
 31     protected static function addInstance($key, self $instance)
 32     {
 33         $key = self::getInstancePoolKey($key);
 34         $class = static::class;
 35         self::$instances[$class][$key] = $instance;
 36     }
 37 
 38     /**
 39      * Checks whether an instance exists for the given key.
 40      *
 41      * @param mixed $key Key
 42      *
 43      * @return bool
 44      */
 45     protected static function hasInstance($key)
 46     {
 47         $key = self::getInstancePoolKey($key);
 48         $class = static::class;
 49         return isset(self::$instances[$class][$key]);
 50     }
 51 
 52     /**
 53      * Returns the instance for the given key.
 54      *
 55      * If the instance does not exist it will be created by calling the $createCallback
 56      *
 57      * @param mixed    $key            Key
 58      * @param callable $createCallback Callback, will be called to create a new instance
 59      *
 60      * @return null|static
 61      */
 62     protected static function getInstance($key, callable $createCallback = null)
 63     {
 64         $args = (array) $key;
 65         $key = self::getInstancePoolKey($args);
 66         $class = static::class;
 67         if (!isset(self::$instances[$class][$key]) && $createCallback) {
 68             $instance = call_user_func_array($createCallback, $args);
 69             self::$instances[$class][$key] = $instance instanceof static ? $instance : null;
 70         }
 71         if (isset(self::$instances[$class][$key])) {
 72             return self::$instances[$class][$key];
 73         }
 74         return null;
 75     }
 76 
 77     /**
 78      * Removes the instance of the given key.
 79      *
 80      * @param mixed $key Key
 81      */
 82     public static function clearInstance($key)
 83     {
 84         $key = self::getInstancePoolKey($key);
 85         $class = static::class;
 86         unset(self::$instances[$class][$key]);
 87     }
 88 
 89     /**
 90      * Clears the instance pool.
 91      */
 92     public static function clearInstancePool()
 93     {
 94         $calledClass = static::class;
 95         // unset instances of calledClass and of all subclasses of calledClass
 96         foreach (self::$instances as $class => $_) {
 97             if ($class === $calledClass || is_subclass_of($class, $calledClass)) {
 98                 unset(self::$instances[$class]);
 99             }
100         }
101     }
102 
103     /**
104      * Returns a string representation for the key.
105      *
106      * The original key can be a scalar value or an array of scalar values
107      *
108      * @param mixed $key Key
109      *
110      * @return string
111      */
112     private static function getInstancePoolKey($key)
113     {
114         return implode('###', (array) $key);
115     }
116 }
117