【问题标题】:Fatal error: Cannot redeclare class CLASSNAME error already tried require_once()致命错误:无法重新声明类 CLASSNAME 错误已经尝试过 require_once()
【发布时间】:2016-12-04 18:11:18
【问题描述】:

我来自 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{ 的左大括号出现错误

希望你能帮我解决这个问题。

谢谢。

【问题讨论】:

  • 好吧,你是对的 require_onceinclude_once。是不是说你不能重新声明“DBHelper”或者类名是什么?
  • @Rasclatt 首先,谢谢。是的,我收到错误致命错误:无法重新声明类 DBHelper
  • 其他原因可能是 1)您使用的名称与已经在其他地方(可能由其他人)创建的类相同,在这种情况下您应该使用命名空间 2)也许您复制了这个文件以重命名和扩展它,忘记更改重复文件上的类名。
  • 另外,如果你只是在做 PHP 新手,我建议使用 PDO 而不是 mysqli_,虽然这是个人喜好,但我认为你会发现绑定值更容易,而且只需一般来说更容易。您可以像$preparedStatement-&gt;execute(array(":0"=&gt;$username,":1"=&gt;$password)); 一样将数组直接放入您的execute(),我发现PDO 更容易自动化和使用,但就像我说的,这是个人喜好。

标签: php mysqli pdo


【解决方案1】:

在 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>';
}

【讨论】:

  • 感谢所有提示。随着我继续学习 PHP 中的 OOP 编程方式,所有这些在将来都会很有用。您实际上是正确的,我不得不将名称空间与 require_once 一起使用来修复错误。我要研究你给出的例子。大多数 OOP 模式和风格与我在 Java 中的做法相似。我需要学习一些关键字和命令。再次感谢。使用命名空间解决了我的问题。
  • 希望其中的一些内容有所帮助,我添加了一些额外的内容,我注意到我没有很好地解决一些问题,或者在某些情况下根本没有解决。干杯
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-17
  • 2014-11-07
  • 2012-07-31
  • 2016-03-25
  • 2017-01-21
  • 1970-01-01
相关资源
最近更新 更多