badsyntax
badsyntax

Reputation: 311

PHP OOP accessing methods in other class

I'm new to doing things the oop way. Here's what I got.

First I've made a class that connects me to my database. Then I made a class to fetch the results from the database.

/engine/classes.php

class DB
{
    public static function dbConnect() 
    {
        $db = new mysqli(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
        if ($db->connect_error) {
        die('A connection to the database cannot be made.');
        }
    }
}

class Blog
{
    public function fetchBlog() 
    {
        DB::dbConnect();
        $results = array();
        if ($blog = $db->query('SELECT * FROM blog')) {
            if ($blog->num_rows) {
                 while ($row = $blog->fetch_object()) {
                     $results[] = $row;
                 }
             $blog->free();
             }
         }
     }
}

Then I have a core.php file where I include my classes.php file and instantiate these classes. Like so

/engine/core.php

require_once 'classes.php';

$con = new DB();
$con->dbConnect();

$blog = new Blog();

Then finally I have my index.php where the I'd like to echo the results I get. That looks like this

index.php

<?php include 'engine/core.php'; ?>
html stuff
<div id="blog">
    <?php
    $blog->fetchBlog();
    if (!count($results)) {
        echo'There are no blog posts at this time.';
    } else {
        foreach ($results as $r) { 
            echo'<div class="blogPost">
                <em>', escape($r->postDate), '</em>
                <h1>', escape($r->postTitle), '</h1>
                <div>', escape($r->postBody), '</div>
            </div>';
        } 
    }

    ?>
</div>

I do have error reporting on and do not get errors on core.php or classes.php. However on my index.php page I am getting these errors

Notice: Undefined variable: db in C:\wamp\www\website\engine\classes.php on line 138
 Fatal error: Call to a member function query() on a non-object in C:\wamp\www\website\engine\classes.php on line 138

How can I correct this? I assume I need a __construct somewhere in there and I also assume I'm not calling the dbConnect method correctly. I have tried a lot of things but listing them here would just be too much? Can anyone tell me what I am doing wrong?

Upvotes: 1

Views: 571

Answers (3)

Jonathan
Jonathan

Reputation: 2877

The issue is that your $db variable is local to the DB::dbConnect() function, which means once that function is done running it is destroyed.

There's also an issue with the $results where you didn't return it from the function or assign a value from the function call.

With the following edits you will be able to make it work, I'll comment it to hopefully allow you to better understand why I've done things the way I did.

/engine/classes.php

class DB
{
    /**
     * keep the variable available for all instances of the DB class since it's static.
     */ 
    static protected $db;

    /**
     * get database instance, connect if necessary
     */
    public static function conn()
    {
        /**
         * automatically connect to the database if it's not connected
         * this is known as lazy loading, which means it only creates
         * the resource at the exact time that it needs it
         */
        if (false === (self::$db instanceof mysqli) {
            self::connect();
        }
        return self::$db;
    }

    /**
     * create a connection to the database
     */
    protected static function connect() 
    {
        self::$db = new mysqli(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
        if (self::$db->connect_error) {
            die('A connection to the database cannot be made.');
        }
    }
}

class Blog
{
    public function fetchBlog() 
    {
        $results = array();
        /**
         * Since the db method is static, you can just call it without an instance
         */
        if ($blog = DB::conn()->query('SELECT * FROM blog')) {
            if ($blog->num_rows) {
                 while ($row = $blog->fetch_object()) {
                     $results[] = $row;
                 }
             $blog->free();
             }
         }
     /**
      * you didn't do anything with the results, presumably you want to return them so you can do something with them
      */
     return $results;
     }

}

/engine/core.php

require_once 'classes.php';

/**
 * It is unnecessary to create an instance of the DB class
 * as all methods are defined statically
 */
//$con = new DB();
//$con->dbConnect();

$blog = new Blog();

index.php

<?php include 'engine/core.php'; ?>
<!-- html stuff -->
<div id="blog">
    <?php
    /**
     * You must assign the output of the function call so you can make use of it
     */
    $results = $blog->fetchBlog();
    if (!count($results)) {
        echo'There are no blog posts at this time.';
    } else {
        foreach ($results as $r) { 
            echo'<div class="blogPost">
                <em>', escape($r->postDate), '</em>
                <h1>', escape($r->postTitle), '</h1>
                <div>', escape($r->postBody), '</div>
            </div>';
        } 
    }

    ?>
</div>

Upvotes: 2

Avinash
Avinash

Reputation: 6174

In you line if ($blog = $db->query('SELECT * FROM blog')) {, $db is never declared.

What you need to do is to return DB object from constructor, so your class DB should look like below:

class DB
{
    public static function dbConnect() 
    {
        $db = new mysqli(DB_HOSTNAME, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
        if ($db->connect_error) {
            die('A connection to the database cannot be made.');
        }

        // Note this line :)
        return $db;

    }
}

Apart from this there are lot many improvements, that can be done in your code. Just to start with I would suggest you to dive into OOP in detail from here: http://php.net/manual/en/language.oop5.php

Off topic but I would like to add few more suggestions. As you have created your DB object creation method as a static. I would suggest to implement Singleton design pattern for such objects because you will need only and only one object of this class across your application. Read More.

Upvotes: 0

seb-o-matic
seb-o-matic

Reputation: 25

In your class Blog you just access a variable $db that is never declared in the line:

if ($blog = $db->query('SELECT * FROM blog')) {

You would have to add a variable $db to your class DB and then create a new instance of that class in your class Blog.

Upvotes: 0

Related Questions