致命错误:无法重新声明类CLASSNAME错误已尝试require_once()

时间:2016-12-04 18:11:18

标签: php mysqli pdo

我来自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 {

的大括号上收到错误

我希望你能帮助我。

谢谢。

1 个答案:

答案 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>';
}