我有一个类userdb
,我在其中声明了一个返回与数据库的连接的函数:
return $con = new PDO("mysql:host=$host;dbname=$db", $user, $pass);
我有各种功能,甚至跨其他类,我必须访问$con
(例如,传递查询或获取数据),但我不能访问这个变量。
有没有更好的方法来定义和使用数据库类?请记住,我还有其他需要访问该课程的userdb
课程。
我建议您为此使用单例模式:
在您的 userdb 类中,声明一个静态属性$scon
:
private static $scon;
并假设您上面提到的函数是 named createConnection()
,您应该创建以下静态方法:
public static function connect() {
if (empty(self::$scon)) {
$instance = new userdb();
self::$scon = $indtance->createConnection();
}
return self::$scon;
}
有了这个,您将能够通过以下方式访问您的 userdb 连接:
userdb::connect();
此外,由于这是一个单例,它只会连接一次,并使用该连接直到脚本结束。
注意(关于依赖注入):由于@KevinM1 提到了Dependency Injection,我必须补充一点,它也是一种可能的、非常优越的解决方案。它要求您使用数据库连接为所有类创建 setConnection() 方法(或抽象祖先),并且在这些类的实例化期间,您可以使用工厂将所需的连接添加到对象。这应该包含在一些类加载器中,这与您的模型结构不同。
看,小菜一碟,但对于小而快的开发,我会坚持使用 Singleton ;)
如果它在一个类中,将实例存储在一个属性中:
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;
好吧,$con 已经是一个对象,因为它正在实例化一个新的 PDO 对象。除非您尝试向 PDO 对象添加功能,否则包装它是没有意义的。
也就是说,与其他对象共享您的 userdb/PDO 对象(取决于您是否坚持使用包装器)的最佳方法是使用Dependency Injection。这是一个花哨的术语,用于将您的数据库传递给任何需要它的对象。由于对象在 PHP 中默认通过引用传递,如果您首先创建 db 对象,则所有接收它作为构造函数/方法参数的对象都将使用同一个实例。
编辑:链接到依赖注入实现
EDIT2:澄清小项目中的DI-
正常的 DI 模式通常需要一个称为 DI Container 的特殊对象。这是一个特殊用途的对象,它会自动将依赖注入到需要它的对象中。对于小型项目,这是矫枉过正的。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。它的使用几乎总是一种设计气味。
在 PHP 中,没有共享内存的概念,并且脚本每次请求执行一次,想要使用单例的唯一原因是可以轻松访问单个资源。由于对象是通过引用传递的,一个实例自然可以与多个对象共享。从那里开始,它是关于良好的设计和授权。
return $this->con
从你的班级以这种方式返回并以这种方式调用它..
$this->classObject->con->prepare();
查看我的视频教程 + 代码以获得全局 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);
}
}
要在类函数或独立函数中使用变量,您需要放置一个全局关键字
$conn=mysql_connect();
function test(){
global $conn;
}
now$conn
将在 test 函数的范围内可用,并且在脚本顶部定义时将在任何地方可用。对于类,您也需要做同样的事情,创建一个类的对象并在函数中将其声明为全局