0
votes

So the scenario is simple. I use class that does something in database but in that class I call another class that also does something in DB.

Thanks, include_once changed to include and it works!

This is what I get:

Fatal error: Call to a member function prepare() on a non-object -> mLog.php on line 20

I use db_config.php to create PDO object and then include it in my classes.

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();
}

1st class 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();
            }
        }
    }

second class that uses first class (fragment because it's big and has many functions)

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();
    }
}
2
The error should also have a file and line number. What does that correspond to? The prepare() call in the Log class or in the second class?Adam

2 Answers

1
votes

You used include_once "db_config.php"; instead of include "db_config.php";.

As I understand from your code, each time you include db_config.php, you will create the database object $DBH.

Since you put it as include_once, it will only run db_config.php once, and in the log class when you try to include it, it will not run - since it has already been included in the Add method.

To improve on this, you should create a class that solely manages (or encapsulate) the PDO object. You can simply create a Singleton class that returns the PDO object, include the class once at the top, and fetch the object where ever you are in the code.

Example:

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

}

Log Class:

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();
        }
    }
}

Usage:

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();
    }
}
0
votes

The scope of $DB isn't within the classes because you haven't passed it into the classes. At the moment its just floating around in global scope, but not within the scope of your classes.

You need to add $DB into the Log class, you can do this as a static variable like so inside your db_config.php

Log::$DB = $DB;

And use like this in your class

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();
        }
    }
}