Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
| 1 | <?php |
||
| 13 | final class Ivory |
||
| 14 | { |
||
| 15 | const VERSION = '0.1.0a1'; |
||
| 16 | |||
| 17 | /** @var ICoreFactory */ |
||
| 18 | private static $coreFactory = null; |
||
| 19 | /** @var TypeRegister */ |
||
| 20 | private static $typeRegister = null; |
||
| 21 | /** @var ISqlPatternParser */ |
||
| 22 | private static $sqlPatternParser = null; |
||
| 23 | /** @var StatementExceptionFactory */ |
||
| 24 | private static $stmtExFactory = null; |
||
| 25 | /** @var IConnection[] map: name => connection */ |
||
| 26 | private static $connections = []; |
||
| 27 | /** @var IConnection|null */ |
||
| 28 | private static $defaultConn = null; |
||
| 29 | /** @var CacheItemPoolInterface|null */ |
||
| 30 | private static $defaultCacheImpl = null; |
||
| 31 | /** @var ICacheControl|null */ |
||
| 32 | private static $globalCacheControl = null; |
||
| 33 | |||
| 34 | |||
| 35 | private function __construct() |
||
| 39 | |||
| 40 | public static function getCoreFactory(): ICoreFactory |
||
| 47 | |||
| 48 | /** |
||
| 49 | * Provides Ivory with a factory for core objects. |
||
| 50 | * |
||
| 51 | * Note that {@link Ivory} caches the objects so setting another core factory is only effective at the very |
||
| 52 | * beginning of working with Ivory. |
||
| 53 | * |
||
| 54 | * @param ICoreFactory $coreFactory |
||
| 55 | */ |
||
| 56 | public static function setCoreFactory(ICoreFactory $coreFactory) |
||
| 60 | |||
| 61 | /** |
||
| 62 | * @return TypeRegister the global type register, used for getting types not defined locally for a connection |
||
| 63 | */ |
||
| 64 | public static function getTypeRegister(): TypeRegister |
||
| 71 | |||
| 72 | public static function getSqlPatternParser(): ISqlPatternParser |
||
| 80 | |||
| 81 | /** |
||
| 82 | * @return StatementExceptionFactory the global statement exception factory, used for emitting the |
||
| 83 | * {@link \Ivory\Exception\StatementException}s upon statement errors; |
||
| 84 | * like the type register, an overriding factory is also defined locally on each |
||
| 85 | * connection - this factory only applies if the local one does not |
||
| 86 | */ |
||
| 87 | public static function getStatementExceptionFactory(): StatementExceptionFactory |
||
| 88 | { |
||
| 89 | if (self::$stmtExFactory === null) { |
||
| 90 | self::$stmtExFactory = self::getCoreFactory()->createStatementExceptionFactory(); |
||
| 91 | } |
||
| 92 | return self::$stmtExFactory; |
||
| 93 | } |
||
| 94 | |||
| 95 | /** |
||
| 96 | * @return ICacheControl cache control used globally, independent of any specific connection |
||
| 97 | */ |
||
| 98 | public static function getGlobalCacheControl(): ICacheControl |
||
| 105 | |||
| 106 | /** |
||
| 107 | * @return CacheItemPoolInterface|null the cache implementation to use for connections which do not set their own |
||
| 108 | * cache, or <tt>null</tt> if no default cache implementation is set up |
||
| 109 | */ |
||
| 110 | public static function getDefaultCacheImpl() |
||
| 114 | |||
| 115 | /** |
||
| 116 | * @param CacheItemPoolInterface|null $cacheItemPool the cache implementation to use for connections which do not |
||
| 117 | * set their own cache, or <tt>null</tt> for no default cache |
||
| 118 | */ |
||
| 119 | public static function setDefaultCacheImpl($cacheItemPool) |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Sets up a new database connection. |
||
| 126 | * |
||
| 127 | * If this is the first connection to set up, it is automatically set as the default connection. |
||
| 128 | * |
||
| 129 | * The connection with the database is not immediately established - just a {@link Connection} object is initialized |
||
| 130 | * and returned, it connects to the database on demand. |
||
| 131 | * |
||
| 132 | * @param mixed $params the parameters for creating the connection; |
||
| 133 | * anything accepted by {@link ConnectionParameters::create()} - one of the following options: |
||
| 134 | * <ul> |
||
| 135 | * <li>a {@link ConnectionParameters} object |
||
| 136 | * <li>a URI, e.g., <tt>"postgresql://usr@localhost:5433/db?connect_timeout=10"</tt> |
||
| 137 | * <li>a PostgreSQL connection string, e.g., |
||
| 138 | * <tt>"host=localhost port=5432 dbname=mydb connect_timeout=10"</tt> |
||
| 139 | * <li>a map of connection parameter keywords to values, e.g., <tt>['host' => '/tmp']</tt> |
||
| 140 | * </ul> |
||
| 141 | * @param string|null $connName name for the connection; |
||
| 142 | * if not given, the database name is considered if it is given within <tt>$params</tt> |
||
| 143 | * or the fallback name <tt>'conn'</tt> is used; |
||
| 144 | * if not given and if the auto-generated name is already taken, it is appended with a |
||
| 145 | * numeric suffix, e.g., <tt>'conn1'</tt>, <tt>'conn2'</tt>, etc. |
||
| 146 | * @return IConnection |
||
| 147 | * @throws ConnectionException if connection name is explicitly specified but a connection with the same name |
||
| 148 | * already exists |
||
| 149 | */ |
||
| 150 | public static function setupNewConnection($params, string $connName = null): IConnection |
||
| 151 | { |
||
| 152 | if (!$params instanceof ConnectionParameters) { |
||
| 153 | $params = ConnectionParameters::create($params); |
||
| 154 | } |
||
| 155 | |||
| 156 | if ($connName === null) { |
||
| 157 | $connName = (isset($params['dbname']) ? $params['dbname'] : 'conn'); |
||
| 158 | $safetyBreak = 10000; |
||
| 159 | for ($i = 1; $i < $safetyBreak; $i++) { |
||
| 160 | if (!isset(self::$connections[$connName . $i])) { |
||
| 161 | $connName .= $i; |
||
| 162 | break; |
||
| 163 | } |
||
| 164 | } |
||
| 165 | if ($i >= $safetyBreak) { |
||
| 166 | throw new \RuntimeException('Error auto-generating name for the new connection: all suffixes taken'); |
||
| 167 | } |
||
| 168 | } |
||
| 169 | |||
| 170 | $conn = self::getCoreFactory()->createConnection($connName, $params); |
||
| 171 | |||
| 172 | if (!self::$connections) { |
||
|
|
|||
| 173 | self::useConnectionAsDefault($conn); |
||
| 174 | } |
||
| 175 | |||
| 176 | self::$connections[$connName] = $conn; |
||
| 177 | |||
| 178 | return $conn; |
||
| 179 | } |
||
| 180 | |||
| 181 | /** |
||
| 182 | * @param string|null $connName name of the connection to get; <tt>null</tt> to get the default connection |
||
| 183 | * @return IConnection |
||
| 184 | * @throws \RuntimeException if the default connection is requested but no connection has been setup yet, or if the |
||
| 185 | * requested connection is not defined |
||
| 186 | */ |
||
| 187 | public static function getConnection(string $connName = null): IConnection |
||
| 188 | { |
||
| 189 | View Code Duplication | if ($connName === null) { |
|
| 190 | if (self::$defaultConn) { |
||
| 191 | return self::$defaultConn; |
||
| 192 | } else { |
||
| 193 | throw new \RuntimeException('No connection has been setup'); |
||
| 194 | } |
||
| 195 | } |
||
| 196 | |||
| 197 | View Code Duplication | if (isset(self::$connections[$connName])) { |
|
| 198 | return self::$connections[$connName]; |
||
| 199 | } else { |
||
| 200 | throw new \RuntimeException('Undefined connection'); |
||
| 201 | } |
||
| 202 | } |
||
| 203 | |||
| 204 | /** |
||
| 205 | * @param IConnection|string $conn (name of) connection to use as the default connection |
||
| 206 | * @throws \RuntimeException if the requested connection is not defined |
||
| 207 | */ |
||
| 208 | public static function useConnectionAsDefault($conn) |
||
| 222 | |||
| 223 | /** |
||
| 224 | * Removes a connection from the register so that it no longer occupies memory. |
||
| 225 | * |
||
| 226 | * @param IConnection|string|null $conn (name of) connection to remove from the register; |
||
| 227 | * <tt>null</tt> to remove the default connection |
||
| 228 | * @throw \RuntimeException if the default connection is requested but no connection has been setup yet, or if the |
||
| 229 | * requested connection is not defined |
||
| 230 | */ |
||
| 231 | public static function dropConnection($conn = null) |
||
| 254 | } |
||
| 255 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)or! empty(...)instead.