Communicating Between Classes

Coding Critique is the place to post source code for peer review by other members of DevNetwork. Any kind of code can be posted. Code posted does not have to be limited to PHP. All members are invited to contribute constructive criticism with the goal of improving the code. Posted code should include some background information about it and what areas you specifically would like help with.

Popular code excerpts may be moved to "Code Snippets" by the moderators.

Moderator: General Moderators

Post Reply
ird
Forum Newbie
Posts: 8
Joined: Thu Mar 13, 2008 12:24 am

Communicating Between Classes

Post by ird »

Hi. I'm currently writing a small CMS (sort of) for personal use.

I'm trying to write it with OOP but it's been nothing but headaches. I'm trying to do a few things and I can't find much info on how to do them.

A) A global class that deals with the database (the connection, queries, etc)
B) Another global class that deals with errors (Handles them, log, etc)
C) Use methods from one object in another object (IE use the database object in another class like "user" to get a users information).

Is there any way to use the database object (And an error handling object that I haven't wrote yet) without passing them to every object I want to use them in.

Here is my working code. If anyone can point me towards a more elegant way to do this, I would appreciate it.

Code: Select all

<?php
require_once('tiff_func.php');
 
class database
{
    private static $db_handle;
 
    function __construct()
    {
        require_once('config/db_conf.php');
        $this->db_handle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS)
            or exit(mysql_error());
        mysql_select_db(MYSQL_DB)
            or exit(mysql_error());
    }
    function query($sql)
    {
        $sql = mysql_real_escape_string($sql);
 
        echo $sql; //debug purposes.
 
        if (empty($sql))
        {
            return NULL; //NO query given.
        }
        else
        {
            $results = mysql_query($sql);
        }
 
        if ($results === TRUE)
        {
            return 1;
        }
        if ($results === FALSE)
        {
            return 0;
        }
 
        if (mysql_num_rows($results) == 1 && mysql_num_fields($results) == 1)
        {
            $results = mysql_fetch_row($results);
            return $results[0];
        }
        while ($tmp = mysql_fetch_assoc($results))
        {
            $resultArr[] = $tmp;
        }
        if (is_array($resultArr[0]) && count($resultArr) == 1)
        {
            return $resultArr[0];
        }
        return $resultArr;
    }
    function result_count($table, $row = NULL, $match1 = NULL, $match2 = NULL)
    {
        if (empty($row))
        {
            $row = '*';
        }
        $sql = "SELECT count($row) FROM $table";
        if (!empty($match1) && empty($match2))
        {
            $sql .= " WHERE $row = '$match1'";
        }
        if (!emptyEx($match1, $match2))
        {
            $sql .= " WHERE $match1 = '$match2'";
        }
        $results = $this->query($sql);
        return $results;
    }
    function __destruct()
    {
        mysql_close($this->db_handle);
    }
}
$db_handle = new database();
 
class input_validator {
    function user_name($user_name) {
        $pattern = "/^[a-zA-Z0-9]*$/";
        $user_name = htmlspecialchars($user_name);
        if (!preg_match($pattern, $user_name))
        {
            //ERROR
            return 0;
        }
        return 1;
    }
}
$input_validator = new input_validator();
 
class user {
    public $current_user;
 
    function __construct($db_handle)
    {
        $this->db_handle = $db_handle;
    }
    function return_all_users()
    {
        $users = $this->db_handle->query("SELECT * FROM userinfo");
        if(empty($users))
        {
            $users = "No users";
        }
        return $users;
    }
}
$user_handle = new user($db_handle);
 
//print all the users in the database.
$users = $user_handle->return_all_users();
print_r($users);
 
 
//check to see if a username is valid (in this case, only alpha numeric)
$user_names = array("ryan", "ry@n");
 
foreach ($user_names as $cur_name)
{
     echo "$cur_name is ";
     if ($input_validator->user_name($cur_name))
     {
          echo "Valid Username <br />";
     }
     else
     {
         echo "Invalid Username <br />";
     }
}
?>
 
And 'tiff_func.php' just contains this function.

Code: Select all

function emptyEx()
{
    if (!(func_num_args() > 0))
    {
        return NULL;
    }
 
    $args = func_get_args();
    
    foreach ($args as $tmp)
    {
        if (empty($tmp)) 
        {
            return 1;
        }
    }
    return 0;
}
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Communicating Between Classes

Post by Christopher »

Using a Registry is an often used solution. However I wonder if you actually have a problem. You say that you have to pass the database class to "every object", but are there really that many objects that need it? Your code only has one. Are you solving a problem that hasn't occured yet?
(#10850)
ird
Forum Newbie
Posts: 8
Joined: Thu Mar 13, 2008 12:24 am

Re: Communicating Between Classes

Post by ird »

I can't seem to find much on a 'registry' with google.

Where can I get more information on implementing one?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: Communicating Between Classes

Post by Christopher »

search for "registry pattern" or even "registry pattern php"
(#10850)
User avatar
Zoxive
Forum Regular
Posts: 974
Joined: Fri Apr 01, 2005 4:37 pm
Location: Bay City, Michigan

Re: Communicating Between Classes

Post by Zoxive »

patternsforphp has some examples as well as many others.

I belive it also was started by someone from here.

http://www.patternsforphp.com/wiki/Registry
ird
Forum Newbie
Posts: 8
Joined: Thu Mar 13, 2008 12:24 am

Re: Communicating Between Classes

Post by ird »

Ah, thank you very much.

This is exactly the type of pattern I was looking for.

Also, thanks for introducing me to such a great PHP site.

:D
ird
Forum Newbie
Posts: 8
Joined: Thu Mar 13, 2008 12:24 am

Re: Communicating Between Classes

Post by ird »

Code: Select all

<pre>
<?php
require_once('tiff_func.php');
 
class core {
    private $objects = array();
    private static $instance = NULL;
 
    private function __construct()
    {
        //private construct
    }
    private function __clone()
    {
        //no cloning
    }
 
    function get_instance()
    {
        if (is_null(self::$instance))
        {
            self::$instance = new self();
        }
        return self::$instance;
    }
 
    function __get($label)
    {
        if (isset($this->objects[$label]))
        {
            return $this->objects[$label];
        }
        return false;
    }
    function __set($label, $object)
    {
        if (!isset($this->objects[$label]))
        {
            $this->objects[$label] = $object;
        }
    }
    function init_class($class) // Make creating the class and putting it into the 'core' easier.
    {
        $object = new $class;
        $this->$class = $object;
 
        return $object;
    }
}
$core = core::get_instance();
 
class database
{
    private static $db_link;
 
    function __construct()
    {
        require_once('config/db_conf.php');
        $this->db_link = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS)
            or exit(mysql_error());
        mysql_select_db(MYSQL_DB)
            or exit(mysql_error());
    }
    function query($sql)
    {
        $sql = mysql_real_escape_string($sql);
 
        echo $sql;
 
        if (empty($sql))
        {
            return NULL; //NO query given.
        }
        else
        {
            $results = mysql_query($sql);
        }
 
        if ($results === TRUE)
        {
            return 1;
        }
        if ($results === FALSE)
        {
            return 0;
        }
 
        if (mysql_num_rows($results) == 1 && mysql_num_fields($results) == 1)
        {
            $results = mysql_fetch_row($results);
            return $results[0];
        }
        while ($tmp = mysql_fetch_assoc($results))
        {
            $result_arr[] = $tmp;
        }
        if (is_array($resultArr[0]) && count($resultArr) == 1)
        {
            return $result_arr[0];
        }
        return $result_arr;
    }
    function result_count($table, $row = NULL, $match1 = NULL, $match2 = NULL)
    {
        if (empty($row))
        {
            $row = '*';
        }
        $sql = "SELECT count($row) FROM $table";
        if (!empty($match1) && empty($match2))
        {
            $sql .= " WHERE $row = '$match1'";
        }
        if (!empty_ex($match1, $match2))
        {
            $sql .= " WHERE $match1 = '$match2'";
        }
        $results = $this->query($sql);
        return $results;
    }
    function __destruct()
    {
        mysql_close($this->db_link);
    }
}
 
class user_managment {
    //required objects
    public $database;
    public $core;
 
    function __construct()
    {
        $core = core::get_instance();
        $this->database = $core->database;
    }
 
    function return_all_users()
    {
        $users = $this->database->query("SELECT * FROM userinfo");
        if(empty($users))
        {
            $users = "No users";
        }
        return $users;
    }
}
 
//setup classes
$database = $core->init_class('database');
$user_managment = $core->init_class('user_managment');
 
//testing
$users = $user_managment->return_all_users();
 
print_r($users);
 
?>
</pre>
 
How about something like this?
User avatar
Mordred
DevNet Resident
Posts: 1579
Joined: Sun Sep 03, 2006 5:19 am
Location: Sofia, Bulgaria

Re: Communicating Between Classes

Post by Mordred »

You seriously miss the point of mysql_real_escape_string() and how it should be used.
Post Reply