这是我的困境,我正在尝试将我的php迁移到更多基于对象的代码与旧样式以及从mysqli到pdo。但是当我这样做时,我开始遇到一些特别针对类和依赖的问题。
例如,我有一个名为pdo_connection.php
的文件,它保存了我的数据库连接信息。
<?php
define("DSN", "mysql:host=localhost;dbname=user_info");
define("USERNAME", "root");
define("PASSWORD", "password");
$options = array(PDO::ATTR_PERSISTENT => TRUE);
try {
$conn = new PDO(DSN,USERNAME,PASSWORD , $options);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $ex) {
Echo "Folowing Problem: ".$ex->getMessage();
exit();
}
现在我有一个名为pdo_user的文件,它将保存一个类和函数来处理实际的mysql查询。
// include_once 'pdo_connection.php';
class data_user
{
public function __construct()
{
include_once 'pdo_connection.php';
}
// Validate User Login
public function val_login($user, $passwd)
{
//include_once 'pdo_connection.php';
$sel = "CALL `user_info`.`sp_user_login`('$user', '$passwd')";
$res = $conn->query($sel);
while ($row = $res->fetch(PDO::FETCH_ASSOC))
{
return($row);
}
}
}
当我调用该函数时,如果include_once'pdo_connection.php'不在公共函数val_login中,则会立即收到错误。
我尝试将它放入__construct或一直在顶部,它总是抱怨Undefined variable: conn in /var/www/html/mysql_pdo/pdo_user.php on line 27
简单的解决方法是将它放在公共函数val_login
中,但我可以看到这是每次调用函数时必须加载的最佳方式。
所以希望有人可以告诉我我错过了什么以及如何加载像conn这样的东西,所有功能都可以访问。
答案 0 :(得分:3)
您的问题是由于variable scoping。
让我们单独查看您的函数,并将pdo_connection.php
的内容移到__construct
方法中,因为它会更好地突出显示问题:
public function __construct()
{
define("DSN", "mysql:host=localhost;dbname=user_info");
define("USERNAME", "root");
define("PASSWORD", "password");
$options = array(PDO::ATTR_PERSISTENT => TRUE);
try {
$conn = new PDO(DSN,USERNAME,PASSWORD , $options);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $ex) {
Echo "Folowing Problem: ".$ex->getMessage();
exit();
}
}
public function val_login($user, $passwd)
{
$sel = "CALL `user_info`.`sp_user_login`('$user', '$passwd')";
$res = $conn->query($sel);
while ($row = $res->fetch(PDO::FETCH_ASSOC))
{
return($row);
}
}
在构造函数中,您将创建名为$conn
的 local 变量。构造函数方法完成后,控制返回到调用上下文,$conn
变量消失。其范围仅在__construct
方法中有效。
如果您希望该连接变量具有更长的生命周期,那么您拥有的唯一真正好的选项(因为构造函数不能返回值)是将该变量存储为class property。一旦这样做,该属性的生命周期将与类实例本身的生命周期相同:
class data_user
{
// This just defines the property
protected $conn;
public function __construct()
{
define("DSN", "mysql:host=localhost;dbname=user_info");
define("USERNAME", "root");
define("PASSWORD", "password");
$options = array(PDO::ATTR_PERSISTENT => TRUE);
try {
// This is setting the property
$this->conn = new PDO(DSN,USERNAME,PASSWORD , $options);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $ex) {
Echo "Folowing Problem: ".$ex->getMessage();
exit();
}
}
public function val_login($user, $passwd)
{
$sel = "CALL `user_info`.`sp_user_login`('$user', '$passwd')";
// This is now accessing the class property and not a local variable
// that is undefined.
$res = $this->conn->query($sel);
while ($row = $res->fetch(PDO::FETCH_ASSOC))
{
return($row);
}
}
}
我还明确建议不在类构造函数中包含其他文件。请考虑这种用法:
define("DSN", "mysql:host=localhost;dbname=user_info");
define("USERNAME", "root");
define("PASSWORD", "password");
$options = array(PDO::ATTR_PERSISTENT => TRUE);
try {
$conn = new PDO(DSN,USERNAME,PASSWORD , $options);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $ex) {
Echo "Folowing Problem: ".$ex->getMessage();
exit();
}
$data_user = new data_user($conn);
$another_object = new another_object($conn);
这会将您的data_user
构造函数更改为:
public function __construct($conn)
{
$this->conn = $conn;
}
哪个更简单,允许您在可能需要数据库连接的其他对象之间重用相同的$conn
对象,并避免在对象构造函数中使用doing work。它还data_user
来自
hdbsql -i 00 -u DDIC -p <password>
hdbsql -i 00 -u SYSTEM -p <password>
类,因此在概念上它更容易,因为该类没有真正的理由知道如何连接到您的数据库。它只需要知道连接本身。
答案 1 :(得分:2)
您可能会遇到一些问题。我试图提供几种解决方案。
首先,您可能需要查看PSR4自动加载和命名空间。文件类是自动的&#39;从给定命名结构的目录加载。一旦我发现了自动加载功能,我就感到惊讶。此外,您可以在PHP(http://php.net/manual/en/function.spl-autoload-register.php)中注册自己的自定义自动加载器。这个想法是,如果可以解析一个类的名称来引用该类的文件,那么它可以被自动加载。没有更多include_once,require_once ...
其次,您可能想要了解依赖注入。对象(在这种情况下是依赖关系)被注入到其他对象中,通常在它们的__construct()方法中。
简单来说,我会改变你的课程:
cmd.CommandText = "sp_addserver";
cmd.Parameters.Clear();
cmd.Parameters.Add(new SqlParameter("@server", "MYNEWSERVER"));
cmd.ExecuteNonQuery();
然后你可以像这样使用它:
<?php
namespace Data;
class User
{
/**
* The PDO connection
*/
private $conn;
/**
* This receives the connection using dependency injection.
* @param \PDO $conn The connection.
* @return null
*/
public function __construct(\PDO $conn)
{
$this -> conn = $conn;
}
// Validate User Login
public function valLogin($user, $passwd)
{
$sel = "CALL `user_info`.`sp_user_login`('$user', '$passwd')";
$res = $this -> conn ->query($sel);
while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
return($row);
}
}
}
希望这有帮助吗?如果您有更多问题,请回复。
另一种选择是使$ conn全局化,这不是一种推荐的方法。
另一个选择是创建一个接收$ connection并设置静态属性的类。这不是最好的方法,但比全局$ conn变量更好。
<?php
define("DSN", "mysql:host=localhost;dbname=user_info");
define("USERNAME", "root");
define("PASSWORD", "password");
$options = array(PDO::ATTR_PERSISTENT => TRUE);
try {
$conn = new PDO(DSN,USERNAME,PASSWORD , $options);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (Exception $ex) {
Echo "Folowing Problem: ".$ex->getMessage();
exit();
}
// The connection is injected into the constructor.
$dataUser = new Data\User($conn);
$userRow = $dataUser -> valLogin($user, $passwd);
然后你的val_login方法如下所示:
class Connection
{
public static $connection;
public function __construct(\PDO $conn)
{
self::$connection = $conn;
}
}