[Patch] For Bug #669 DB::singleton()
| From: | Scott Barron | Date: | Mon, 17 May 2004 00:43:59 +0000 |
| Subject: | [Patch] For Bug #669 DB::singleton() | ||
| Groups: | php.pear.dev | ||
| Request: | Send a blank email to pear-dev+get-29295@lists.php.net to get a copy of this message | ||
Hi,
I too would find this pretty usefull so I made an attempt at it. I've
attached the patch and test file.
I used Log::singleton() as a template for this so it looks pretty
similar to that. I added the $_id to DB_common and set it in the
constructor instead of setting it in the constructor of each DB type (as
Log does). I'm not sure how necessary it is, it seems to only come in
handy in the way that the phpt test file uses it. I'd appreciate
comments on this part of the addition.
Thanks
-Scott
Index: DB.php =================================================================== RCS file: /repository/pear/DB/DB.php,v retrieving revision 1.58 diff -u -r1.58 DB.php --- DB.php 13 Mar 2004 16:17:19 -0000 1.58 +++ DB.php 17 May 2004 00:43:18 -0000 @@ -320,6 +320,44 @@ } // }}} + // {{{ &singleton() + + /** + * Attemps to return a reference to a concrete DB instancem only + * creating a new instance if no DB instances with the same parameters + * currently exists. + * + * You should use this if there are multiple places you might create + * a DB instance, you don't want to create multiple instances, and you + * don't want to check for the existance of one each time. The singleton + * pattern does all the checking work for you. + * + * <b>You MUST call this method with the $var = &DB::singleton() syntax. + * Without the ampersand (&) in front of the method name, you will not get + * a reference, you will get a copy>.</b> + * + * @param string $type database type, for example "mysql" + * @param array $options associative array of option names and values + * + * @return object a new DB object. On error, an error object. + * + * @see DB_common::setOption() + * @access public + */ + function &singleton($type, $options = false) + { + static $instances; + if (!isset($instances)) $instances = array(); + + $signature = serialize(array($type, $options)); + if (!isset($instances[$signature])) { + $instances[$signature] = &DB::factory($type, $options); + } + + return $instances[$signature]; + } + + // }}} // {{{ &connect() /** Index: DB/common.php =================================================================== RCS file: /repository/pear/DB/DB/common.php,v retrieving revision 1.102 diff -u -r1.102 common.php --- DB/common.php 1 May 2004 02:42:11 -0000 1.102 +++ DB/common.php 17 May 2004 00:43:19 -0000 @@ -117,6 +117,14 @@ */ var $dbh; + /** + * Instance-specific unique identification number. + * + * @var integer + * @access private + */ + var $_id = 0; + // }}} // {{{ toString() @@ -149,6 +157,7 @@ function DB_common() { $this->PEAR('DB_Error'); + $this->_id = md5(microtime()); } // }}} --TEST-- DB::factory --SKIPIF-- <?php chdir(dirname(__FILE__)); require_once './skipif.inc'; ?> --FILE-- <?php // -*- C++ -*- require_once './include.inc'; require_once 'DB.php'; $backends = array( 'dbase', 'fbsql', 'ibase', 'ifx', 'msql', 'mssql', 'mysql', 'mysqli', 'oci8', 'odbc', 'pgsql', 'sqlite', 'sybase', ); foreach ($backends as $name) { $obj1 = &DB::singleton($name); $obj2 = &DB::singleton($name); if (is_a($obj1, "DB_{$name}") && is_a($obj2, "DB_{$name}")) { echo "Two DB_{$name} objects.\n"; } if ($obj1->_id == $obj2->_id) { echo "The objects have the same ID.\n"; } } ?> --GET-- --POST-- --EXPECT-- Two DB_dbase objects. The objects have the same ID. Two DB_fbsql objects. The objects have the same ID. Two DB_ibase objects. The objects have the same ID. Two DB_ifx objects. The objects have the same ID. Two DB_msql objects. The objects have the same ID. Two DB_mssql objects. The objects have the same ID. Two DB_mysql objects. The objects have the same ID. Two DB_mysqli objects. The objects have the same ID. Two DB_oci8 objects. The objects have the same ID. Two DB_odbc objects. The objects have the same ID. Two DB_pgsql objects. The objects have the same ID. Two DB_sqlite objects. The objects have the same ID. Two DB_sybase objects. The objects have the same ID.
Index: DB.php =================================================================== RCS file: /repository/pear/DB/DB.php,v retrieving revision 1.58 diff -u -r1.58 DB.php --- DB.php 13 Mar 2004 16:17:19 -0000 1.58 +++ DB.php 17 May 2004 00:43:18 -0000 @@ -320,6 +320,44 @@ } // }}} + // {{{ &singleton() + + /** + * Attemps to return a reference to a concrete DB instancem only + * creating a new instance if no DB instances with the same parameters + * currently exists. + * + * You should use this if there are multiple places you might create + * a DB instance, you don't want to create multiple instances, and you + * don't want to check for the existance of one each time. The singleton + * pattern does all the checking work for you. + * + * <b>You MUST call this method with the $var = &DB::singleton() syntax. + * Without the ampersand (&) in front of the method name, you will not get + * a reference, you will get a copy>.</b> + * + * @param string $type database type, for example "mysql" + * @param array $options associative array of option names and values + * + * @return object a new DB object. On error, an error object. + * + * @see DB_common::setOption() + * @access public + */ + function &singleton($type, $options = false) + { + static $instances; + if (!isset($instances)) $instances = array(); + + $signature = serialize(array($type, $options)); + if (!isset($instances[$signature])) { + $instances[$signature] = &DB::factory($type, $options); + } + + return $instances[$signature]; + } + + // }}} // {{{ &connect() /** Index: DB/common.php =================================================================== RCS file: /repository/pear/DB/DB/common.php,v retrieving revision 1.102 diff -u -r1.102 common.php --- DB/common.php 1 May 2004 02:42:11 -0000 1.102 +++ DB/common.php 17 May 2004 00:43:19 -0000 @@ -117,6 +117,14 @@ */ var $dbh; + /** + * Instance-specific unique identification number. + * + * @var integer + * @access private + */ + var $_id = 0; + // }}} // {{{ toString() @@ -149,6 +157,7 @@ function DB_common() { $this->PEAR('DB_Error'); + $this->_id = md5(microtime()); } // }}} --TEST-- DB::factory --SKIPIF-- <?php chdir(dirname(__FILE__)); require_once './skipif.inc'; ?> --FILE-- <?php // -*- C++ -*- require_once './include.inc'; require_once 'DB.php'; $backends = array( 'dbase', 'fbsql', 'ibase', 'ifx', 'msql', 'mssql', 'mysql', 'mysqli', 'oci8', 'odbc', 'pgsql', 'sqlite', 'sybase', ); foreach ($backends as $name) { $obj1 = &DB::singleton($name); $obj2 = &DB::singleton($name); if (is_a($obj1, "DB_{$name}") && is_a($obj2, "DB_{$name}")) { echo "Two DB_{$name} objects.\n"; } if ($obj1->_id == $obj2->_id) { echo "The objects have the same ID.\n"; } } ?> --GET-- --POST-- --EXPECT-- Two DB_dbase objects. The objects have the same ID. Two DB_fbsql objects. The objects have the same ID. Two DB_ibase objects. The objects have the same ID. Two DB_ifx objects. The objects have the same ID. Two DB_msql objects. The objects have the same ID. Two DB_mssql objects. The objects have the same ID. Two DB_mysql objects. The objects have the same ID. Two DB_mysqli objects. The objects have the same ID. Two DB_oci8 objects. The objects have the same ID. Two DB_odbc objects. The objects have the same ID. Two DB_pgsql objects. The objects have the same ID. Two DB_sqlite objects. The objects have the same ID. Two DB_sybase objects. The objects have the same ID.