我来自Java编程,我正在尝试将我的知识应用于PHP中的OOP样式编程。
所以,我尝试创建一个实用程序类来连接数据库,就像我通常在Java中创建一个静态方法来获取数据库连接一样。
但是,花了好几个小时后我仍然无法解决错误。
DBHelper.php
<?php
class DBHelper
{
protected $db_name = 'myDb';
protected $db_user = 'root';
protected $db_pass = '';
protected $db_host = 'localhost';
public function obtainConnection()
{
$mysqli_instance = new mysqli($this->db_host, $this->db_user, $this->db_pass, $this->db_name);
/* check connection */
if (mysqli_connect_errno()) {
printf("Connect failed: %s\n", mysqli_connect_error());
exit();
}
return $mysqli_instance;
}
}
?>
此文件中没有错误
然后我尝试在名为login.php
的login.php
<?php
if (isset($_POST['submit'])) {
include "/DBUtility/DBHelper.php";
$username = $_POST['username']; //s means string
$password = $_POST['password']; // s means string
echo "<br/> Username value: " . $username;
echo "<br />Password value: " . $password;
}
if (empty($username) || empty($password) ) {
echo "Fill out the fields!";
} else {
//PREPARE THE PreparedStatment or Stored Procedure
$dbHelper = new DBHelper();
$connection = $dbHelper->obtainConnection();
$preparedStatement = $connection->prepare('CALL getUserRoleByLogin(?, ?)'); //getUserRoleByLogin() is the name of stored proc in mysql db
$preparedStatement->bind_param('ss', $username, $password); //assign arguments to ? ?
$preparedStatement->execute();//execute the stored procedure. This will return a result
$userRole = $preparedStatement->store_result();
$countOfRows = $preparedStatement->num_rows;
?>
我阅读了有关Fatal error: Cannot redeclare class CLASSNAME
错误的所有相关问题。我尝试按照许多人给出的说明使用require_once("DBHelper.php");
代替include("DBHelper.php");
但仍然无法摆脱错误。
我尝试使obtainConnection()
静态并通过DBHelper::obtainConnection();
调用它,但没有运气。相同的错误消息。
我在class DBHelper
{
我希望你能帮助我。
谢谢。
答案 0 :(得分:2)
在PHP中进行OOP时应该做的一些提示:
1)我可能会重新考虑不直接将db凭证烘焙到您的类中,如果您想在线下实现UI控制机制,则通过UI修改它们会变得更难/更麻烦。相反,尝试制作一个define或者一个json
pref文件或一个包含数组的动态创建的php
文件。我会做一个定义,因为它最容易演示:
<强> /config.php 强>
# You can create a series of defines including the database
define('DB_HOST','localhost');
define('DB_NAME','dbname');
define('DB_USER','root');
define('DB_PASS','dbpassword');
# To maximize compatibility it's helpful to define fwd/back slash
define('DS',DIRECTORY_SEPARATOR);
# It is helpful to create path defines for easy file inclusion
define('ROOT_DIR',__DIR__);
define('CLASSES',ROOT_DIR.DS.'classes');
# Start session
session_start();
2)在config.php
文件中创建一个类autoloader,然后您就不必在页面中手动包含/要求类。它会自动包含它们:
spl_autoload_register(function($class) {
if(class_exists($class))
return;
# This will turn a namespace/class into a path so should turn:
# $db = new \DBUtility\DBHelper();
# into:
# /var/www/domain/httpdocs/classes/DBUtility/DBHelper.php
$path = str_replace(DS.DS,DS,CLASSES.DS.str_replace('\\',DS,$class).'.php');
# If the class file is located in the class folder, it will include it
if(is_file($path))
include_once($path);
});
3)我将创建静态连接,因此您不必每次都创建新连接(我也会使用PDO):
<强> /classes/DBUtility/DBHelper.php 强>
<?php
namespace DBUtility;
class DBHelper
{
protected $query;
private static $con;
public function connection()
{
# This will send back the connection without making a new one
if(self::$con instanceof \PDO)
return self::$con;
# I like to catch any pdo exceptions on connection, just incase.
try {
# Assign the connection
self::$con = new \PDO('mysql:host='.DB_HOST.';dbname='.DB_NAME,DB_USER,DB_PASS);
}
catch(\PDOException $e) {
# Here you can just die with a more user-friendly error.
# It would be helpful to save the actual error to a log file
$msg = $e->getMessage();
# I would put your log outside the root or in a protected folder
$txt = realpath(ROOT_DIR.DS.'..').DS.'errors'.DS.'sql.txt';
# Make a directory if none set
if(!is_dir(pathinfo($txt,PATHINFO_DIRNAME))) {
# Make the directory
if(mkdir(pathinfo($txt,PATHINFO_DIRNAME),0744,true)) {
# Save to log file
file_put_contents($txt,$msg.PHP_EOL);
}
}
else {
# Save to log file
file_put_contents($txt,$msg.PHP_EOL);
}
die("Site is under maintenance.");
}
}
# It would be helpful to create a query that will bind and not bind
public function query($sql,$bind = false)
{
if(is_array($bind)) {
foreach($bind as $key => $value) {
$sKey = ":{$key}";
$bindArr[$sKey] = $value;
}
$this->query = $this->connection()->prepare($sql);
$this->query->execute($bindArr);
}
else {
# The second "query" on this is the method from PDO, not the
# "query" method from this class
$this->query = $this->connection()->query($sql);
}
return $this;
}
public function getResults()
{
if(empty($this->query))
return false;
while($result = $this->query->fetch(\PDO::FETCH_ASSOC)) {
$row[] = $result;
}
return (isset($row))? $row : false;
}
}
# If your page ends with a php tag, you should just remove it. It will
# protect against empty spaces that may cause "header already sent" errors
3a)我使用类似的东西来自动加载功能:
<强> /classes/Helper.php 强>
class Helper
{
public static function autoload($function)
{
if(function_exists($function))
return;
$path = ROOT_DIR.DS.'functions'.DS.$function.'.php';
if(is_file($path))
include_once($path);
}
}
4)创建有用/可重用的函数或类/方法
<强> /functions/getUserRole.php 强>
function getUserRole($username,$password,\DBUtility\DBHelper $DBHelper)
{
return $DBHelper->query('CALL getUserRoleByLogin(:0, :1)',array($username,$password))->getResults();
}
<强>的index.php 强>
# Include the config file
require_once(__DIR__.DIRECTORY_SEPARATOR.'config.php');
if (isset($_POST['submit'])) {
# No need for this line ->> include "/DBUtility/DBHelper.php";
# Use trim to remove empty spaces on the left and right
$username = trim($_POST['username']);
$password = trim($_POST['password']);
}
if (empty($username) || empty($password) ) {
echo "Fill out the fields!";
} else {
# User our function autoloader to include this function
Helper::autoload('getUserRole');
# Use the function and inject the DB class
$userRoles = getUserRole($username,$password,new \DBUtility\DBHelper());
$count = count($userRoles);
echo "Count: {$count}";
echo '<pre>';
print_r($userRoles);
echo '</pre>';
}