我有一个名为userdb
的类,在其中声明了一个返回数据库连接的函数:
return $con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
我有很多功能,甚至跨越其他类,在这些功能中,我需要访问$con
(例如传递查询或获取数据),但我无法访问此变量。
是否有更好的方法来定义和使用数据库类?请记住,我还有其他类需要访问userdb
类。
我有一个名为userdb
的类,在其中声明了一个返回数据库连接的函数:
return $con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
我有很多功能,甚至跨越其他类,在这些功能中,我需要访问$con
(例如传递查询或获取数据),但我无法访问此变量。
是否有更好的方法来定义和使用数据库类?请记住,我还有其他类需要访问userdb
类。
$scon
:private static $scon;
假设你提到的函数名为createConnection()
,那么你需要创建以下静态方法:
public static function connect() {
if (empty(self::$scon)) {
$instance = new userdb();
self::$scon = $indtance->createConnection();
}
return self::$scon;
}
有了这个,你将能够通过以下方式访问你的userdb连接:
userdb::connect();
由于这是一个单例模式,它只会连接一次,并使用该连接直到脚本结束。
注(关于依赖注入):由于@KevinM1提到了依赖注入,我必须补充说明,这也是一种可能且更优秀的解决方案。它要求您为所有使用数据库连接的类创建一个setConnection()方法(或Abstract祖先),并在这些类的实例化期间,您可以使用工厂将所需的连接添加到对象中。这应该包装在某个类加载器内,该加载器知道您的模型结构。
看,很简单,但对于小而快速的开发,我会坚持使用Singleton ;)
global $con
。为了防止这种情况发生,并且为了保持面向对象编程的思路,引入 Singleton 在这里是一个不错的选择。 - aorcsik如果它在一个类中,将实例存储在属性中:
class userDB
{
public $dbCon = false;//because you want to access the instance
//from outside the class, I have made the property public
function connect()
{
$con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
$this->dbCon = $con;
}
}
在课堂外访问它:
$useDBInstance->dbCon;
return $this->con
从你的类中以这种方式返回并以这种方式调用它。
$this->classObject->con->prepare();
嗯,$con将已经是一个对象,因为它正在实例化一个新的PDO对象。除非你想要为你的PDO对象添加功能,否则包装它是没有意义的。
话虽如此,与其他对象共享你的userdb/PDO对象(取决于你是否坚持使用包装器)的最佳方法是使用依赖注入。这是一个花哨的术语,用于将你的数据库传递给任何需要它的对象。由于在PHP中,默认情况下对象是按引用传递的,如果你首先创建你的数据库对象,所有接收它作为构造函数/方法参数的对象都将使用同一个单一实例。
编辑:依赖注入实现的链接
编辑2:关于小项目中的DI的澄清 -
通常的DI模式通常需要一个特殊的对象,称为DI容器。这是一个特殊的使用对象,它会自动将依赖注入到需要它的对象中。对于小项目来说,这有点过度设计了。简单、低复杂性版本的DI只需:
class SomeClass {
protected $db;
public function __construct($db) {
$this->db = $db;
}
}
class SomeClass2 {
public function SomeMethod($db) {
// do something with the db
}
}
$db = new PDO(/* connection string */);
$obj = new SomeClass($db, /* other constructor args */);
// or
$obj2 = new SomeClass2(/* constructor args */);
$obj2->someMethod($db, /* method args */);
神奇的是,由于在PHP中默认情况下通过引用传递对象,$obj和$obj2正在使用相同的数据库连接。
整个想法是通过没有静态方法来避免破坏范围或封装,并确保类及其方法明确说明它们需要什么才能工作。
单例模式恰恰相反。它们通过静态方法访问,绕过了范围,由于它们被调用而不是传递,因此它们从不出现在方法签名中,因此不熟悉代码的任何人都不会意识到这个隐藏的要求。 甚至是Erich Gamma,曾经帮助规范Singleton Pattern的人之一,也对此表示后悔:
在PHP中,没有共享内存的概念,脚本每次请求执行一次,使用单例模式的唯一原因是为了方便访问单个资源。由于对象是按引用传递的,一个实例可以自然地与多个对象共享。从那里开始,重点是良好的设计和委派。我赞成放弃Singleton。它的使用几乎总是设计上的问题。
看看我的视频教程+代码,了解PHP全局变量的替代方法。
你做错了。如果你计划在函数中创建连接并将其存储在那里,你需要使用静态变量。否则,每次函数调用都会连接。我的教程解释了常规函数中静态变量的概念。
如果不够清楚,请告诉我,我会尽力回答你的问题。
这里是一些代码来配合说明:
/**
* Arguments are none or [$db, [$user, [$pass[, $host]]]].
*
* @return PDO
*/
function PdoDb(){
static $con = null; // I'm explicit :)
// Every time you pass Arguments you reconnect
if(func_num_args()){
$args = array_pad(func_get_args(), 4, null);
list($db, $user, $pass, $host) = $args;
if(empty($user)) $user = 'root';
if(empty($host)) $host = 'localhost';
$con = new PDO("mysql:host={$host};dbname={$db}", $user, $pass);
}
if(empty($con)){
trigger_error('Provide arguments to connect first.', E_USER_ERROR);
return null;
}
return $con;
}
// First run (provide arguments to connect)
PdoDb($db, $user, $pass, $host);
PdoDb($db); // Works if you connect root@localhost with no password
// From here on (it returns PDO)
PdoDb()->DoStuffOfPdo();
一旦连接成功,它将保持连接状态。但是您可以通过提供参数随时重新连接。
class connectdb
{
protected static $_instance = NULL;
private function __construct()
{
}
public function getinstance()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
public function connect()
{
$this->connection =new PDO("mysql:host=$host;dbname=$db", $user, $pass);
}
}
如果想在类函数或独立函数中使用变量,需要使用global关键字进行声明
$conn=mysql_connect();
function test(){
global $conn;
}
$conn
将可用,并且当在脚本顶部定义时,它将在任何地方都可用。对于类也需要做同样的事情,创建一个类的对象并在函数内声明为全局变量。