Ошибка области - вызов функции-члена prepare() для объекта без объекта

Итак, сценарий прост. Я использую класс, который что-то делает в базе данных, но в этом классе я вызываю другой класс, который также делает что-то в БД.

Спасибо, include_once изменен, чтобы включить, и он работает!

Это то, что я получаю:

Неустранимая ошибка: вызов функции-члена Подготовьте() к не-объекту → mLog.php в строке 20

Я использую db_config.php для создания объекта PDO, а затем включаю его в свои классы.

db_config.php

try
{
    $DBH = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);

    $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
}
catch (PDOException $e)
{
    echo $e->getMessage();
}

1-й класс mLog.php

<?php

    class Log
    {
        public static function Add($action)
        {
            try
            {
                include_once "db_config.php";

                $ip = $_SERVER['REMOTE_ADDR'];

                $time = date('Y-m-d');

                $values = array($ip, $action, $time);
//ERROR NEXT LINE
                $STH = $DBH->prepare("INSERT INTO log (ip, action, time)
                                      VALUES (?, ?, ?)");

                $STH->execute($values);

                $DBH = null;
                $STH = null;
            }
            catch (PDOException $e)
            {
                echo $e->getMessage();
            }
        }
    }

второй класс, который использует первый класс (фрагмент, потому что он большой и имеет много функций)

public static function Add($catName, $catDescr = "", $catImgURL = "", $catSubLevel = 0, $catSubID = 0)
{
    try
    {
        include_once "db_config.php";
        include_once "mLog.php";

        $values = array($catName, $catDescr, $catImgURL, $catSubLevel, $catSubID);
        $STH = $DBH->prepare("INSERT INTO cat (catName, catDescr, catImg, catSubLevel, catSubID)
                              VALUES (?, ?, ?, ?, ?)");

        $STH->execute($values);

        $DBH = null;
        $STH = null;

        //HERE IT IS
        Log::Add("Added category 111" . $catName);

        return true;
    }
    catch (PDOException $e)
    {
        echo $e->getMessage();
    }
}

Ответ 1

Вместо include "db_config.php"; вы использовали include_once "db_config.php";.

Как я понимаю из вашего кода, каждый раз, когда вы включаете db_config.php, вы создадите объект базы данных $DBH.

Поскольку вы указали его как include_once, он будет запускать только db_config.php один раз, а в классе журнала, когда вы попытаетесь его включить, он не будет запущен - поскольку он уже включен в метод добавления.

Чтобы улучшить это, вы должны создать класс, который только управляет (или инкапсулирует) объект PDO. Вы можете просто создать класс Singleton, который возвращает объект PDO, включить класс один раз вверху и извлечь объект, где бы вы ни находились в коде.

Пример:

DBAccess.php

class DBAccess extends Singleton{

    // there is a getInstance() method in the Singleton abstract class

    private $dbh;

    // The PDO object is created only once when the first getInstance() is called in Singleton.
    function __construct(){
        try
        {
            $this->dbh = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);

            $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
        }
        catch (PDOException $e)
        {
            echo $e->getMessage();
        }

    }

    /**
     * Get the PDO object
     * @return object
     */
    public static function getDBH(){
        return self::getInstance()->dbh;
    }

}

Класс журнала:

class Log
{
    public static function Add($action)
    {
        try
        {
            $DBH = DBAccess::getDBH();

            $ip = $_SERVER['REMOTE_ADDR'];

            $time = date('Y-m-d');

            $values = array($ip, $action, $time);

            $STH = $DBH->prepare("INSERT INTO log (ip, action, time)
                                  VALUES (?, ?, ?)");

            $STH->execute($values);
        }
        catch (PDOException $e)
        {
            echo $e->getMessage();
        }
    }
}

Использование:

include_once ( 'db_config.php'); include_once ( 'mLog.php');

public static function Add($catName, $catDescr = '', $catImgURL = '', $catSubLevel = 0, $catSubID = 0)
{
    try
    {

        $DBH = DBAccess::getDBH();

        $values = array($catName, $catDescr, $catImgURL, $catSubLevel, $catSubID);

        $STH = $DBH->prepare("INSERT INTO cat (catName, catDescr, catImg, catSubLevel, catSubID)
                              VALUES (?, ?, ?, ?, ?)");

        $STH->execute($values);

        $DBH = null;

        Log::Add("Added category 111" . $catName);

        return true;
    }
    catch (PDOException $e)
    {
        echo $e->getMessage();
    }
}

Ответ 2

Объем $DB не входит в классы, потому что вы не передали его в классы. На данный момент он просто плавает в глобальной области действия, но не входит в объем ваших классов.

Вам нужно добавить $DB в класс Log, вы можете сделать это как статическую переменную, подобную этой внутри db_config.php

Log::$DB = $DB;

И используйте это в своем классе

class Log
{
    public static $DB;

    public static function Add($action)
    {
        try
        {
            include_once "db_config.php";

            $ip = $_SERVER['REMOTE_ADDR'];

            $time = date('Y-m-d');

            $values = array($ip, $action, $time);
            $STH = self::$DBH->prepare("INSERT INTO log (ip, action, time)
                                  VALUES (?, ?, ?)");

            $STH->execute($values);

            self::$DBH = null;
            $STH = null;
        }
        catch (PDOException $e)
        {
            echo $e->getMessage();
        }
    }
}