瀏覽代碼

Redesign how Predis\ConnectionFactory works and make more sense out of it.

Daniele Alessandri 13 年之前
父節點
當前提交
728afe7fcb

+ 3 - 1
FAQ.PERFORMANCES.md

@@ -55,7 +55,9 @@ name) and let Predis using it. __phpiredis__ is a C-based extension that wraps _
 official Redis C client library) with a thin layer that exposes its features to PHP. You will now
 get the benefits of a faster protocol parser just by adding a single line of code in your application:
 
-    Predis\ConnectionFactory::define('tcp', '\Predis\Network\PhpiredisConnection');
+    $client = new Predis\Client('tcp://127.0.0.1', array(
+        'connections' => array('tcp' => 'Predis\Network\PhpiredisConnection')
+    ));
 
 As simple as it is, nothing will really change in the way you use the library in your application. So,
 how fast is it now? There are not much improvements for inline or short bulk replies (e.g. _SET_ or

+ 4 - 3
README.md

@@ -113,11 +113,12 @@ class MyConnectionClass implements Predis\Network\IConnectionSingle
     // implementation goes here
 }
 
-// Let Predis automatically use your own class to handle the default TCP connection
-Predis\ConnectionFactory::define('tcp', 'MyConnectionClass');
+// Let Predis automatically use your own class to handle connections identified by the tcp prefix.
+$client = new Predis\Client('tcp://127.0.0.1', array(
+    'connections' => array('tcp' => 'MyConnectionClass')
+));
 ```
 
-
 You can have a look at the `Predis\Network` namespace for some actual code that gives a better
 insight about how to create new connection classes.
 

+ 8 - 43
lib/Predis/Client.php

@@ -32,7 +32,7 @@ class Client
     private $options;
     private $profile;
     private $connection;
-    private $connectionFactory;
+    private $connections;
 
     /**
      * Initializes a new client with optional connection parameters and client options.
@@ -43,15 +43,16 @@ class Client
     public function __construct($parameters = null, $options = null)
     {
         $options = $this->filterOptions($options);
-        $profile = $options->profile;
 
+        $profile = $options->profile;
         if (isset($options->prefix)) {
             $profile->setProcessor($options->prefix);
         }
 
         $this->options = $options;
         $this->profile = $profile;
-        $this->connectionFactory = $options->connections;
+        $this->connections = $options->connections;
+
         $this->connection = $this->initializeConnection($parameters);
     }
 
@@ -94,51 +95,15 @@ class Client
      */
     private function initializeConnection($parameters)
     {
-        if ($parameters === null) {
-            return $this->createConnection(new ConnectionParameters());
-        }
-
-        if (is_array($parameters)) {
-            if (isset($parameters[0])) {
-                $cluster = $this->options->cluster;
-                foreach ($parameters as $node) {
-                    $connection = $node instanceof IConnectionSingle ? $node : $this->createConnection($node);
-                    $cluster->add($connection);
-                }
-                return $cluster;
-            }
-            return $this->createConnection($parameters);
-        }
-
         if ($parameters instanceof IConnection) {
             return $parameters;
         }
 
-        return $this->createConnection($parameters);
-    }
-
-    /**
-     * Creates a new connection to a single server with the provided parameters.
-     *
-     * @param mixed $parameters Connection parameters.
-     * @return IConnectionSingle
-     */
-    protected function createConnection($parameters)
-    {
-        $connection = $this->connectionFactory->create($parameters);
-        $parameters = $connection->getParameters();
-
-        if (isset($parameters->password)) {
-            $command = $this->createCommand('auth', array($parameters->password));
-            $connection->pushInitCommand($command);
-        }
-
-        if (isset($parameters->database)) {
-            $command = $this->createCommand('select', array($parameters->database));
-            $connection->pushInitCommand($command);
+        if (is_array($parameters) && isset($parameters[0])) {
+            return $this->connections->createCluster($this->options->cluster, $parameters, $this->profile);
         }
 
-        return $connection;
+        return $this->connections->create($parameters, $this->profile);
     }
 
     /**
@@ -168,7 +133,7 @@ class Client
      */
     public function getConnectionFactory()
     {
-        return $this->connectionFactory;
+        return $this->connections;
     }
 
     /**

+ 72 - 50
lib/Predis/ConnectionFactory.php

@@ -11,7 +11,10 @@
 
 namespace Predis;
 
+use Predis\Profiles\IServerProfile;
 use Predis\Network\IConnectionSingle;
+use Predis\Network\IConnectionCluster;
+use Predis\Profiles\ServerProfile;
 
 /**
  * Provides a default factory for Redis connections that maps URI schemes
@@ -22,22 +25,28 @@ use Predis\Network\IConnectionSingle;
  */
 class ConnectionFactory implements IConnectionFactory
 {
-    private static $globalSchemes;
-
-    private $instanceSchemes = array();
+    private $schemes;
 
     /**
-     * @param array $schemesMap Map of URI schemes to connection classes.
+     * Initializes a new instance of the default connection factory class used by Predis.
      */
-    public function __construct(Array $schemesMap = null)
+    public function __construct()
     {
-        $this->instanceSchemes = self::ensureDefaultSchemes();
+        $this->schemes = $this->getDefaultSchemes();
+    }
 
-        if (isset($schemesMap)) {
-            foreach ($schemesMap as $scheme => $initializer) {
-                $this->defineConnection($scheme, $initializer);
-            }
-        }
+    /**
+     * Returns a named array that maps URI schemes to connection classes.
+     *
+     * @return array Map of URI schemes and connection classes.
+     */
+    protected function getDefaultSchemes()
+    {
+        return array(
+            'tcp' => 'Predis\Network\StreamConnection',
+            'unix' => 'Predis\Network\StreamConnection',
+            'http' => 'Predis\Network\WebdisConnection',
+        );
     }
 
     /**
@@ -46,81 +55,61 @@ class ConnectionFactory implements IConnectionFactory
      * callable objects are used for lazy initialization of connection objects.
      *
      * @param mixed $initializer FQN of a connection class or a callable for lazy initialization.
+     * @return mixed
      */
-    private static function checkConnectionInitializer($initializer)
+    protected function checkInitializer($initializer)
     {
         if (is_callable($initializer)) {
-            return;
+            return $initializer;
         }
 
         $initializerReflection = new \ReflectionClass($initializer);
 
-        if (!$initializerReflection->isSubclassOf('\Predis\Network\IConnectionSingle')) {
+        if (!$initializerReflection->isSubclassOf('Predis\Network\IConnectionSingle')) {
             throw new \InvalidArgumentException(
                 'A connection initializer must be a valid connection class or a callable object'
             );
         }
-    }
 
-    /**
-     * Ensures that the default global URI schemes map is initialized.
-     *
-     * @return array
-     */
-    private static function ensureDefaultSchemes()
-    {
-        if (!isset(self::$globalSchemes)) {
-            self::$globalSchemes = array(
-                'tcp'   => '\Predis\Network\StreamConnection',
-                'unix'  => '\Predis\Network\StreamConnection',
-            );
-        }
-
-        return self::$globalSchemes;
+        return $initializer;
     }
 
     /**
-     * Defines a new URI scheme => connection class relation at class level.
-     *
-     * @param string $scheme URI scheme
-     * @param mixed $connectionInitializer FQN of a connection class or a callable for lazy initialization.
+     * {@inheritdoc}
      */
-    public static function define($scheme, $connectionInitializer)
+    public function define($scheme, $initializer)
     {
-        self::ensureDefaultSchemes();
-        self::checkConnectionInitializer($connectionInitializer);
-        self::$globalSchemes[$scheme] = $connectionInitializer;
+        $this->schemes[$scheme] = $this->checkInitializer($initializer);
     }
 
     /**
-     * Defines a new URI scheme => connection class relation at instance level.
-     *
-     * @param string $scheme URI scheme
-     * @param mixed $connectionInitializer FQN of a connection class or a callable for lazy initialization.
+     * {@inheritdoc}
      */
-    public function defineConnection($scheme, $connectionInitializer)
+    public function undefine($scheme)
     {
-        self::checkConnectionInitializer($connectionInitializer);
-        $this->instanceSchemes[$scheme] = $connectionInitializer;
+        unset($this->schemes[$scheme]);
     }
 
     /**
      * {@inheritdoc}
      */
-    public function create($parameters)
+    public function create($parameters, IServerProfile $profile = null)
     {
         if (!$parameters instanceof IConnectionParameters) {
-            $parameters = new ConnectionParameters($parameters);
+            $parameters = new ConnectionParameters($parameters ?: array());
         }
 
         $scheme = $parameters->scheme;
-        if (!isset($this->instanceSchemes[$scheme])) {
+        if (!isset($this->schemes[$scheme])) {
             throw new \InvalidArgumentException("Unknown connection scheme: $scheme");
         }
 
-        $initializer = $this->instanceSchemes[$scheme];
+        $initializer = $this->schemes[$scheme];
         if (!is_callable($initializer)) {
-            return new $initializer($parameters);
+            $connection = new $initializer($parameters);
+            $this->prepareConnection($connection, $profile ?: ServerProfile::getDefault());
+
+            return $connection;
         }
 
         $connection = call_user_func($initializer, $parameters);
@@ -133,4 +122,37 @@ class ConnectionFactory implements IConnectionFactory
 
         return $connection;
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function createCluster(IConnectionCluster $cluster, $parameters, IServerProfile $profile = null)
+    {
+        foreach ($parameters as $node) {
+            $cluster->add($node instanceof IConnectionSingle ? $node : $this->create($node, $profile));
+        }
+
+        return $cluster;
+    }
+
+    /**
+     * Prepares a connection object after its initialization.
+     *
+     * @param IConnectionSingle $connection Instance of a connection object.
+     * @param IServerProfile $profile $connection Instance of a connection object.
+     */
+    protected function prepareConnection(IConnectionSingle $connection, IServerProfile $profile)
+    {
+        $parameters = $connection->getParameters();
+
+        if (isset($parameters->password)) {
+            $command = $profile->createCommand('auth', array($parameters->password));
+            $connection->pushInitCommand($command);
+        }
+
+        if (isset($parameters->database)) {
+            $command = $profile->createCommand('select', array($parameters->database));
+            $connection->pushInitCommand($command);
+        }
+    }
 }

+ 28 - 1
lib/Predis/IConnectionFactory.php

@@ -11,6 +11,9 @@
 
 namespace Predis;
 
+use Predis\Profiles\IServerProfile;
+use Predis\Network\IConnectionCluster;
+
 /**
  * Interface that must be implemented by classes that provide their own mechanism
  * to create and initialize new instances of Predis\Network\IConnectionSingle.
@@ -19,11 +22,35 @@ namespace Predis;
  */
 interface IConnectionFactory
 {
+    /**
+     * Defines or overrides the connection class identified by a scheme prefix.
+     *
+     * @param string $scheme URI scheme identifying the connection class.
+     * @param mixed $initializer FQN of a connection class or a callable object for lazy initialization.
+     */
+    public function define($scheme, $initializer);
+
+    /**
+     * Undefines the connection identified by a scheme prefix.
+     *
+     * @param string $scheme Parameters for the connection.
+     */
+    public function undefine($scheme);
+
     /**
      * Creates a new connection object.
      *
      * @param mixed $parameters Parameters for the connection.
      * @return Predis\Network\IConnectionSingle
      */
-    public function create($parameters);
+    public function create($parameters, IServerProfile $profile = null);
+
+    /**
+     * Prepares a cluster of connection objects.
+     *
+     * @param IConnectionCluster Instance of a connection cluster class.
+     * @param array $parameters List of parameters for each connection object.
+     * @return Predis\Network\IConnectionCluster
+     */
+    public function createCluster(IConnectionCluster $cluster, $parameters, IServerProfile $profile = null);
 }

+ 5 - 1
lib/Predis/Options/ClientConnectionFactory.php

@@ -30,7 +30,11 @@ class ClientConnectionFactory extends Option
             return $value;
         }
         if (is_array($value)) {
-            return new ConnectionFactory($value);
+            $factory = $this->getDefault();
+            foreach ($value as $scheme => $initializer) {
+                $factory->define($scheme, $initializer);
+            }
+            return $factory;
         }
     }