php - MySQL 单例类与递归函数冲突(PHP)

标签 php mysql singleton hierarchical-data

我有一个用 PHP 编写的 MySQL 单例类。其代码如下:

class Database {
    private $_result = NULL;
    private $_link = NULL;
    private $_config = array();
    private static $_instance = NULL; 

    // Return singleton instance of MySQL class
    public static function getInstance(array $config = array()) {
        if (self::$_instance === NULL) {
            self::$_instance = new self($config);
        }

        return self::$_instance;
    }

    // Private constructor
    private function __construct(array $config) {
        if (count($config) < 4) {
            throw new Exception('Invalid number of connection parameters');  
        }

        $this->_config = $config;
    } 

    // Prevent cloning class instance
    private function __clone() {}

    // Connect to MySQL
    private function connect() {
        // Connect only once
        static $connected = FALSE;

        if ($connected === FALSE) {
            list($host, $user, $password, $database) = $this->_config;

            if ((!$this->_link = mysqli_connect($host, $user, $password, $database))) {
                throw new Exception('Error connecting to MySQL : ' . mysqli_connect_error());
            }

            $connected = TRUE;

            unset($host, $user, $password, $database);      
        }
    } 

    // Perform query
    public function query($query) {
        if (is_string($query) and !empty($query)) {
            $this->connect();
            if ((!$this->_result = mysqli_query($this->_link, $query))) {
                throw new Exception('Error performing query ' . $query . ' Message : ' . mysqli_error($this->_link));
            }
        }
    }

    // Fetch row from result set
    public function fetch() {
        if ((!$row = mysqli_fetch_object($this->_result))) {
            mysqli_free_result($this->_result);
            return FALSE;
        }

        return $row;
    }

    // Get insertion ID
    public function getInsertID() {
        if ($this->_link !== NUlL) {
            return mysqli_insert_id($this->_link); 
        }

        return NULL;  
    }

    // Count rows in result set
    public function countRows() {
        if ($this->_result !== NULL) {
           return mysqli_num_rows($this->_result);
        }

        return 0;
    }  

    // Close the database connection
    function __destruct() {
        is_resource($this->_link) AND mysqli_close($this->_link);
    }    
}

我还有这个递归函数,它必须返回完整的类别树(SQL 表及其内容可以在 here 中找到):

function getCategories($parent = 0) {
    $html = '<ul>';    
    $query = "SELECT * FROM `categories` WHERE `category_parent` = '$parent'";
    $database->query($query);    
    while($row = $database->fetch()) {
        $current_id = $row->category_id;
        $html .= '<li>' . $row->category_name;
        $has_sub = 0;
        $query = "SELECT `category_parent` FROM `categories` WHERE `category_parent` = '$current_id'";
        $database->query($query);
        $has_sub = $database->countRows();

        if ($has_sub > 0) {        
            $html .= getCategories($current_id);
        }

        $html .= '</li>';
    }

    $html .= '</ul>';
    return $html;
}

现在的问题是该函数仅返回 3 个类别,而不是完整的树。我使用普通 MySQL 函数(mysql_query()、mysql_fetch_object() 等)重写了该函数,它返回了正确的结果。

所以我的结论是该类有问题。请注意,我在大多数项目中都使用了此类,但从未遇到过此问题。

知道什么吗?

谢谢。

编辑:尝试使其返回关联数组

function getCategories($parent = 0) {
    global $database;
    $categories = array();

    $query = "SELECT * FROM `categories` WHERE `category_parent` = '$parent'";
    $database->query($query);    
    while($row = $database->fetch()) {
        $categories[] = array('id' => $row->category_id, 'name' => $row->category_name);        
    }

    for ($i = 0; $i < count($categories); $i++) {

        $categories[$i]['id']['children'] = getCategories($categories[$i]['id']);

    }

    return $categories;
}

上面的代码返回以下数组,但不太好:

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => Categoria 1
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 4
                            [name] => Categoria 1.1
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 7
                                            [name] => Categoria 1.1.2
                                            [children] => Array
                                                (
                                                )

                                        )

                                )

                        )

                    [1] => Array
                        (
                            [id] => 5
                            [name] => Categoria 1.2
                            [children] => Array
                                (
                                )

                        )

                    [2] => Array
                        (
                            [id] => 6
                            [name] => Categoria 1.3
                            [children] => Array
                                (
                                )

                        )

                )

        )

    [1] => Array
        (
            [id] => 2
            [name] => Categoria 2
            [children] => Array
                (
                )

        )

    [2] => Array
        (
            [id] => 3
            [name] => Categoria 3
            [children] => Array
                (
                )

        )
)

最佳答案

您看到的问题是您在第一个查询上运行了其他查询。因此,在递归第一个分支之后,函数会失败,因为它返回到原始 which 循环,并发现它已经位于第一个分支的结果行的末尾(3 级递归) .

一种快速解决方法是使用两个循环而不是一个循环来重写函数。您还可以通过减少必须进行的数据库调用次数来优化该函数。

您的第一个查询没问题。但在 while 循环中,只需获取适当的 idname 元素并将它们存储在数组中。然后重新循环刚刚创建的数组以进行递归。此外,您可以通过不运行“检查”查询来消除多个查询。只需递归 - 如果 id:name 数组中没有元素 - 返回一个空字符串。

编辑:示例(未经测试)

function getCategories($parent = 0) {
    $categories = array();
    $html = "<ul>";
    $query = "SELECT * FROM `categories` WHERE `category_parent` = '$parent'";
    $database->query($query);    
    while($row = $database->fetch()) {
        $categories[$row->category_id] = $row->category_name;
    }
    foreach($categories as $cid=>$category) {
        $html .= "<li>{$row->category_name}";
        $inner = getCategories($cid);
        if($inner != "<ul></ul>")
            $html .= $inner;
        $html .= "</li>"
    }
    $html .= "</ul>";
    return $html;
}

关于php - MySQL 单例类与递归函数冲突(PHP),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3337840/

相关文章:

qt - Qt 的 GUI 编程中的单例是邪恶的吗?

php - 如何修复 PHP 表单验证器错误?

php - 使用 phpexcel 选择所有列将 xlsx 导入到 mysql

php - MySQL - 每个类别都有一个单独的 id

java - 使用 CrudRepository 仅插入一条记录

python - 两个相似的单例概念,为什么字典式可以工作而简单变量不行?

java - 我的 Property Loader 单例线程安全吗?

php - 使用 VichUploaderBundle 将图像列表设置为实体

Javascript 从 PHP 读取 XML 无法读取属性

mysql 用字母和单词对单元格进行排序