CRUD

Real-World OOP With PHP and MySQL

Numerous examples from robots to bicycles have been offered as “easy” explanations of what OOP is. I’ve opted to show you how OOP works with a real-life example, for a programmer. By creating a MySQL CRUD class you can easily create, read, update and delete entries in any of your projects, regardless of how the database is designed.

Setting up the skeleton of our class is fairly simple once we figure out exactly what we need. First we need to make sure that we can do our basic MySQL functions. In order to do this, we need the following functions:

  • Select
  • Insert
  • Delete
  • Update
  • Connect
  • Disconnect

Those seem pretty basic, but I’m sure that as we go through, we’ll notice that a lot of them utilize some similar aspects, so we may have to create more classes. Here is what your class definition should look like. Notice that I made sure that the methods were created with the public keyword.

class Database
{
	public function connect()	{	}
	public function disconnect()	{	}
	public function select()		{	}
	public function insert()		{	}
	public function delete()		{	}
	public function update()	{	}
}

function connect()

This function will be fairly basic, but creating it will require us to first create a few variables. Since we want to make sure that they can’t be accessed from outside our class, we will be setting them as private. These variables will be used to store the host, username, password and database for the connection. Since they will pretty much remain constant throughout, we don’t even need to create modifier or accessor methods for it. After that, we’d just need to create a simple mysql statement to connect to the database. Of course, since as programmers we always have to assume the user (even if it is us) will do something stupid, lets add an extra layer of precaution. We can check if the user has actually connected to the database first, and if they have, there really isn’t a need to re-connect. If they haven’t then we can use their credentials to connect.

private db_host = ‘’; 
private db_user = ‘’; 
private db_pass = ‘’; 
private db_name = ‘’; 

public function connect()
    {
        if(!$this->con)
        {
            $myconn = @mysql_connect($this->db_host,$this->db_user,$this->db_pass);
            if($myconn)
            {
                $seldb = @mysql_select_db($this->db_name,$myconn);
                if($seldb)
                {
                    $this->con = true; 
                    return true; 
                } else
                {
                    return false; 
                }
            } else
            {
                return false; 
            }
        } else
        {
            return true; 
        }
    }

As you can see, it makes use of some basic mysql functions and a bit of error checking to make sure that things are going according to plan. If it connects to the database successfully it will return true, and if not, it will return false. As an added bonus it will also set the connection variable to true if the connection was successfully complete.

public function disconnect()

This function will simply check our connection variable to see if it is set to true. If it is, that means that it is connected to the database, and our script will disconnect and return true. If not, then there really isn’t a need to do anything at all.

public function disconnect()
{
	if($this->con)
	{
		if(@mysql_close())
		{
                       $this->con = false; 
			return true; 
		}
		else
		{
			return false; 
		}
	}
}	

public function select()

This is the first function where things begin to get a little complicated. Now we will be dealing with user arguments and returning the results properly. Since we don’t necessarily want to be able to use the results right away we’re also going to introduce a new variable called result, which will store the results properly. Apart from that we’re also going to create a new function that checks to see if a particular table exists in the database. Since all of our CRUD operations will require this, it makes more sense to create it separately rather than integrating it into the function. In this way, we’ll save space in our code and as such, we’ll be able to better optimize things later on. Before we go into the actual select statement, here is the tableExists function and the private results variable.

private $result = array(); 

private function tableExists($table)
    {
        $tablesInDb = @mysql_query('SHOW TABLES FROM '.$this->db_name.' LIKE "'.$table.'"');
        if($tablesInDb)
        {
            if(mysql_num_rows($tablesInDb)==1)
            {
                return true; 
            }
            else
            { 
                return false; 
            }
        }
    }

This function simply checks the database to see if the required table already exists. If it does it will return true and if not, it will return false.

public function select($table, $rows = '*', $where = null, $order = null)
    {
        $q = 'SELECT '.$rows.' FROM '.$table;
        if($where != null)
            $q .= ' WHERE '.$where;
        if($order != null)
            $q .= ' ORDER BY '.$order;
        if($this->tableExists($table))
       {
        $query = @mysql_query($q);
        if($query)
        {
            $this->numResults = mysql_num_rows($query);
            for($i = 0; $i < $this->numResults; $i++)
            {
                $r = mysql_fetch_array($query);
                $key = array_keys($r); 
                for($x = 0; $x < count($key); $x++)
                {
                    // Sanitizes keys so only alphavalues are allowed
                    if(!is_int($key[$x]))
                    {
                        if(mysql_num_rows($query) > 1)
                            $this->result[$i][$key[$x]] = $r[$key[$x]];
                        else if(mysql_num_rows($query) < 1)
                            $this->result = null; 
                        else
                            $this->result[$key[$x]] = $r[$key[$x]]; 
                    }
                }
            }            
            return true; 
        }
        else
        {
            return false; 
        }
        }
else
      return false; 
    }

While it does seem a little scary at first glance, this function really does a whole bunch of things. First off it accepts 4 arguments, 1 of which is required. The table name is the only thing that you need to pass to the function in order to get results back. However, if you want to customize it a bit more, you can do so by adding which rows will be pulled from the database, and you can even add a where and order clause. Of course, as long as you pass the first value, the result will default to their preset ones, so you don’t have to worry about setting all of them. The bit of code right after the arguments just serves to compile all our arguments into a select statement. Once that is done ,a check is done to see if the table exists, using our prior tableExists function. If it exists, then the function continues onwards and the query is performed. If not, it will fail.

The next section is the real magic of the code. What it does is gather the columns and data that was requested from the database. It then assigns it to our result variable. However, to make it easier for the end user, instead of auto-incrementing numeric keys, the names of the columns are used. In case you get more than one result each row that is returned is stored with a two dimensional array, with the first key being numerical and auto-incrementing, and the second key being the name of the column. If only one result is returned, then a one dimensional array is created with the keys being the columns. If no results are turned then the result variable is set to null. As I said earlier, it seems a bit confusing, but once you break things down into their individual sections, you can see that they are fairly simple and straightforward.

public function insert()

This function is a lot simpler than our prior one. It simply allows us to insert information into the database. As such we will require an additional argument to the name of the table. We will require a variable that corresponds to the values we wish to input. We can simply separate each value with a comma. Then, all we need to do is quickly check to see if our tableExists, and then build the insert statement by manipulating our arguments to form an insert statement. Then we just run our query.

public function insert($table,$values,$rows = null)
    {
        if($this->tableExists($table))
        {
            $insert = 'INSERT INTO '.$table;
            if($rows != null)
            {
                $insert .= ' ('.$rows.')'; 
            }

            for($i = 0; $i < count($values); $i++)
            {
                if(is_string($values[$i]))
                    $values[$i] = '"'.$values[$i].'"';
            }
            $values = implode(',',$values);
            $insert .= ' VALUES ('.$values.')';
            $ins = @mysql_query($insert);            
            if($ins)
            {
                return true; 
            }
            else
            {
                return false; 
            }
        }
    }

As you can see, this function is a lot simpler than our rather complex select statement. Our delete function will actually be even simpler.

public function delete()

This function simply deletes either a table or a row from our database. As such we must pass the table name and an optional where clause. The where clause will let us know if we need to delete a row or the whole table. If the where clause is passed, that means that entries that match will need to be deleted. After we figure all that out, it’s just a matter of compiling our delete statement and running the query.

public function delete($table,$where = null)
    {
        if($this->tableExists($table))
        {
            if($where == null)
            {
                $delete = 'DELETE '.$table; 
            }
            else
            {
                $delete = 'DELETE FROM '.$table.' WHERE '.$where; 
            }
            $del = @mysql_query($delete);

            if($del)
            {
                return true; 
            }
            else
            {
               return false; 
            }
        }
        else
        {
            return false; 
        }
    }

And finally we get to our last major function. This function simply serves to update a row in the database with some new information. However, because of the slightly more complex nature of it, it will come off as a bit larger and infinitely more confusing. Never fear, it follows much of the same pattern of our previous function. First it will use our arguments to create an update statement. It will then proceed to check the database to make sure that the tableExists. If it exists, it will simply update the appropriate row. The hard part, of course, comes when we try and create the update statement. Since the update statement has rules for multiple entry updating (IE – different columns in the same row via the cunning use of comma’s), we will need to take that into account and create a way to deal with it. I have opted to pass the where clause as a single array. The first element in the array will be the name of the column being updated, and the next will be the value of the column. In this way, every even number (including 0) will be the column name, and every odd number will be the new value. The code for performing this is very simple, and is presented below outside the function:

for($i = 0; $i < count($where); $i++)
            {
                if($i%2 != 0)
                {
                    if(is_string($where[$i]))
                    {
                        if(($i+1) != null)
                            $where[$i] = '"'.$where[$i].'" AND ';
                        else
                            $where[$i] = '"'.$where[$i].'"';
                    }
                   else 
                   { 
                        if(($i+1) != null)
                            $where[$i] = $where[$i]. ' AND ';
                        else
                            $where[$i] = $where[$i];
                  }
                }
            }

The next section will create the part of the update statement that deals with actually setting the variables. Since you can change any number of values, I opted to go with an array where the key is the column and the value is the new value of the column. This way we can even do a check to see how many different values were passed to be updated and can add comma’s appropriately.

$keys = array_keys($rows); 
            for($i = 0; $i < count($rows); $i++)
            {
                if(is_string($rows[$keys[$i]]))
                {
                    $update .= $keys[$i].'="'.$rows[$keys[$i]].'"';
                }
                else
                {
                    $update .= $keys[$i].'='.$rows[$keys[$i]];
                }
                // Parse to add commas
                if($i != count($rows)-1)
                {
                    $update .= ','; 
                }
            }

Now that we’ve got those two bits of logic out of the way, the rest of the update statement is easy. Here it is presented below:

public function update($table,$rows,$where)
    {
        if($this->tableExists($table))
        {
            // Parse the where values
            // even values (including 0) contain the where rows
            // odd values contain the clauses for the row
            for($i = 0; $i < count($where); $i++)
            {
                if($i%2 != 0)
                {
                    if(is_string($where[$i]))
                    {
                        if(($i+1) != null)
                            $where[$i] = '"'.$where[$i].'" AND ';
                        else
                            $where[$i] = '"'.$where[$i].'"';
                    }
                }
            }
            $where = implode('=',$where);
            
            
            $update = 'UPDATE '.$table.' SET ';
            $keys = array_keys($rows); 
            for($i = 0; $i < count($rows); $i++)
           {
                if(is_string($rows[$keys[$i]]))
                {
                    $update .= $keys[$i].'="'.$rows[$keys[$i]].'"';
                }
                else
                {
                    $update .= $keys[$i].'='.$rows[$keys[$i]];
                }
                
                // Parse to add commas
                if($i != count($rows)-1)
                {
                    $update .= ','; 
                }
            }
            $update .= ' WHERE '.$where;
            $query = @mysql_query($update);
            if($query)
            {
                return true; 
            }
            else
            {
                return false; 
            }
        }
        else
        {
            return false; 
        }
    }

Now that we have that we’ve finished our last function, our simple CRUD interface for MySQL is complete. You can now create new entries, read specific entries from the database, update entries and delete things. Also, be creating and reusing this class you’ll find that you are saving yourself a lot of time and coding. Ah, the beauty of object oriented programming.

The Use

So we've got our class all made, but how do we use it? This part is simple. Lets start by creating a very simple system database to use in our testing. I created a database called test, and then ran the MySQL statment. You can place it in any database that you like, just make sure that you change the connection variables at the top of the script to match:

The first line is commented out simply because not everyone will need it. If you need to run that more than once, you will need to uncomment it the second time to ensure that it creates the table.

Now that our table is created and populated, it's time to run a few simple queries on it.

&lt?php;
include('crud.php');
$db = new Database();
$db->connect();
$db->select('mysqlcrud');
$res = $db->getResult();
print_r($res);
?>

If done correctly, you should see the following:

Likewise we can go a step further and run an update query, and then output the results:

&lt?php;
$db->update('mysqlcrud',array('name'=>'Changed!'),array('id',1));
$db->update('mysqlcrud',array('name'=>'Changed2!'),array('id',2));
$res = $db->getResult();
print_r($res);
?>

We should see this

Now for a simple insert statement:

;&lt?php;
$db->insert('mysqlcrud',array(3,"Name 4","this@wasinsert.ed"));
$res = $db->getResult();
print_r($res);
?>

Tags: mysql
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://www.enversalih.com enver

    clean and simple example. thanks a lot.

  • kailas

    nice work.i like this site.

  • http://www.goingson.be Rob

    I love commenters like YOZ.

    As soon as someone else’s code is too hard to read you complain, yet when someone else’s code is space out with separate easy to follow lines you’re the first to cry n00b.

    I was able to follow the code and it resemble how I write as well.

    Great tuturial. If may add:

    I you standard dize you db naming and tablie naming and most importantly field naming you can stream line the insert and edit functions by a large amount.

    Here is my insertFromPost function let me know what you think:

    field names have a prefix like user_login, user_pass, etc…

    function insertFromPost( $table , $prefix )
    {
    foreach( $_POST as $k => $v )
    {
    if( ereg( “^”.$prefix , $k ) )
    {
    $fields .= $k . “, “;
    $values .= “‘” . mysql_escape_string( $v ) . “‘, “;

    }
    }

    $fields = ereg_replace( “, $” , “” , $fields );
    $values = ereg_replace( “, $” , “” , $values );

    $q = “INSERT INTO “.$table.” (“.$fields.”) VALUES (“.$values.”)”;
    return $q;
    }

  • http://ronny-andre.no Ronny

    How well does this work with advanced SQL queries?

    Or is it possible to extend the class to work with nesten queries?

  • Cody

    Just out of curiosity, where is the variable ‘con’ used ($this->con) defined. Should it not be defined with the instance variables?

  • http://www.windmedia.no windir

    Finally someone who have understood that the “bicycle” and “car” examples for explaining OOP are useless…

    I might have overlooked it, but you don’t show what the getResult() looks like?

  • obSedrick
  • Rocky

    I really think the OO method should only extend the query,

    $q = “SELECT * FROM `table`”;
    $res = $db->query($q);

    which would be a rewrite of a standard mysql query

    class connection {

    function connect(){

    $c = mysql_connect($this->host, $this->username, $this->password);
    mysql_select_db($this->database);

    }

    function query($string){
    return mysql_query($string) or die(mysql_error());
    }
    }
    $db = new connection;
    // Database Object
    // Database Logic
    // Database Functions

    // Any other functions you wish to re-right.
    // We are basicly taking plain mysql functions and trading them for OOPs // CORE FUNCTIONALITY.
    // We can also trigger our own errors and check if a connection is active within the class.

    When connecting we will be passing our function something to use to connect to the database at the core value of each object we will be instating, a instance of that object.

    We will then render our objects into a page after we include them into a file.

    The class could extend fetching:
    mysql_fetch_array($result);
    mysql_fetch_assoc($result);

    OR you could throw it as a object:
    In which case u would use: mysql_fetch_object($result);

    The hole idea of the class is to pass and control the data while obtaining, clean, practical code which will take care of all database logic.

  • Rocky

    Another thing is that you will be able to instate pre-defined functions to clean / sort user-input or you can write your own working programs to filter and do checking.

    - You could report errors within the query, you could report failed inserts into a database,

  • http://www.danbeland.com Dan Beland

    Good stuff… the only thing that seems odd to me is how you refer to columns/fields in the database as ‘rows’. This could potentially be very confusing for beginners that don’t have a solid grasp on databases.

    For example:
    $q = ‘SELECT ‘.$rows.’ FROM ‘.$table;

    This could just be a matter of opinion, but I think that should be
    $q = ‘SELECT ‘.$fields.’ FROM ‘.$table;

    Especially since PHP refers to it as fields in it’s functions:
    # mysql_field_flags
    # mysql_field_len
    # mysql_field_name
    etc…

    Anyways, I’m just being picky. Good job!

  • php

    why don’t we just use php adodb and be done with it. no need to recreate everything from scratch
    .

  • Mike

    I’m new to OO so I was working through this tutorial line by line and running it locally. In your connection section in the actual tutorial you have
    private db_host ”;
    private db_user ”;
    private db_pass ”;
    private db_name ”;

    I typed this exactly and php gave me an error. Obviously I was frustrated, so I downloaded the .zip and noticed you had $ in front of each variable and I realized you must have left them out in the tutorial on accident. Hopefully this will help any other newbies with this tutorial.

  • Dani

    I am trying to convince myself to some OOP in PHP, but …

    What does the example in this tutorial give me for an advantage compared to procedural method? I only see a bunch functions nothing really special :(

    It’s nicely explained (has some shortcomings when it comes to security but that should be covered in another tutorial) but do you really need go OO for this?

  • http://www.calliarc.com Hemadri

    Hi

    Thank you for sharing nice thought, I found two bugs in your code. In update function if we pass two parameter for while condition it appends.

    In select function, if the database having only single row it shows some wrong output..

    Can you please check and modify your code. Please email me your code so that I will test some more advanced…

    Thanks

  • rajveer patel

    very very great job

  • Dan

    Sorry but even for being an example there are far too much lines.
    This not coding with extended layout for didactive purposes, this is taking detours.

    Especially the update function is a real joke.

    @Angelo : u might wanna read this http://be2.php.net/manual/en/control-structures.foreach.php and also using @ in front of every mysql function is bad.

  • http://www.arabaoyunlari60.com Araba Oyunları

    Thank you , very good, admin

  • http://www.jsall.blogspot.com/ Nayana Adassuriya

    can any body explain me the purpose or mean of the code in update function line no 14

    if(($i+1) != null)

    i cant understand the real logic there
    i guess it should be

    if($where[$i+1] = null)

    all php expert ,reply me soon

  • VIVEK PRASAD

    It is a very nice tutorial for fresher php developer like me

  • T

    Good tutorial for people new to PHP and OOP; however, you do not need separate functions for the CRUD [Create, Read, Update, & Delete] functionality when all you need is a simple Query function because sometimes you need more advanced queries than what can be created when working with in this type of limitation. A singleton design pattern also benefits DB classes as it allows you to use one connection across an entire framework and reduce overhead and increase performance. I agree with a few of the earlier replies about there being redundant code and useless additional code that could be refactored into more efficient code…

  • WebX

    I think the whole premise behind writing a OOP class to an existing Mysql class is rather silly, dangerous and a good reason why PHP received the black eye that it has over the years concerning security holes.

    Although the tutorial based an example for OOP programming in an Mysql environment, it completely rendered SQL injection out. The main issues that I have found is that there is no direct reference to standard (old and new) mysql functions to sanitize data.

    Example_1 provides a little better way of going about an INSERT or UPDATE statement.

    Example_1:
    ==============
    $newNote = addslashes($newNote);
    $newNote = htmlspecialchars($newNote);
    mysql_real_escape_string(trim($newNote));
    ==============

    I can now INSERT newNote without much worry as long as I also sanitized the data coming in from whatever $_REQUEST method was used in my form (IE. $_GET, $_POST, $_COOKIE…etc) using string length, intval, trim or regex expressions (etc…..) to make extra certain the data coming down to the mysql portion of my script is already cleansed for use.

    Another trick for returning results (and one that was briefly mentioned above) is what Example_2 can provide for ease of use anywhere.

    Example_2
    ================
    function options()
    {
    global $products;
    $query = ‘SELECT * FROM `category` LIMIT 0, 100′;
    $get_data = mysql_query($query);
    if (!$get_data || mysql_num_rows($get_data) stripslashes($t['id']), ‘name’ => stripslashes($t['name']));
    }
    return $products;
    }

    // call the above function
    options();

    //spit out the results
    //could add more error checking here such as is_array() or a whole host of // other array checking functions

    foreach ($products as $opt)
    {
    print (” {$opt['name']} \n”);
    }
    =================

    In short, data sanitation is the biggest issue you will ever have to deal with concerning PHP and Mysql. You can create miles of code in OOP fashion and loose track of what exactly it is that supposedly saves you time and effort. Just compare the above OOP class to a standard Mysql function and return code set. All of the above “OOP code” is literally reinventing the wheel, presenting obvious holes for SQL injections and yet I can see that some had no issues snapping the code up and probably pasting it into their own scripts.

    In conclusion, tutorials are nice. Examples are nice, however the one true tutorial all should be reading and learning from is coding PHP securely. Now, before anybody lambastes me for my own examples, just know that I am not going to provide an entire script to emphasize a point. nor spend half a night providing an example for somebody to skin the cat another way more “proficiently”. Each to their own, just do it securely.

  • WebX

    Welp, that was what I was afraid of. Formatting of my PHP code examples are all screwed up and missing another variable return in the for loop, but oh well….no points for prettiness tonight I guess.

  • tom

    thanks, grate

  • Luis Alfonso

    wuaa esto es genial, lastima que me cueste un poco entender porq no hablo ingles!!!

  • Zoran

    Thanks for this tutorial, it is not optimized, but it’s a good starting point for writing better CRUD class. All those who complain can simply just offer a better tutorial or be silent.

  • Von

    Thanks for your time and knowledge. Cool! highly recommended to every OOP newbie like me.

  • http://lahmam.com Mehdi Lahmam B.

    Hi there,

    a little correction for update() function.

    Line 237 : if($where[$i+1] != null) instead of if($i+1 != null)
    Line 238 : $where[$i] = ‘=”‘.$where[$i].’” AND ‘; //missing =

    Thanks to nettuts and their contributors for that wonderful work :)

  • http://www.ameerpetstudent.com Billa Rajinikar

    very godd tutorial

  • odel

    hi! everyody… nice tutorial as always. a trade mark of nettuts?

    i’m new to all these and just don’t know the difference between these two:
    $query = @mysql_query($q) and $query = mysql_query($q)

    i hope someone can clarify this matter for me.

    tia

  • Yash

    it jus avoid warning

  • http://www.netcodeman.com/ Custom PHP

    Interesting Tutorial. Thanks!

  • Hans-Kristian

    It is NOT object-oriented to wrap functions in classes like this. A common misunderstanding.

  • jobish

    Great ………….

    Thank you dear

  • djazzc

    There is a typo in your download code making the update function not working (correctly).

    line 245:

    $where = implode(”,$where);

    should be:

    $where = implode(‘=’,$where);

    Apart from that thanks for a nice tutorial

  • viml

    u are not considered the network traffic,
    if ur db server in the another host you cannot get desired result

  • http://www.deSendesign.com tahir karaca

    hi,

    thanks for class.
    But results is multiplied in $db->getResults() expression for every query. example :

    $db->select(‘table1_tb’);
    $arr1 = $db->getResult();

    $db->select(‘table2_tb’);
    $arr2 = $db->getResult();

    $db->select(‘table3_tb’);
    $arr3 = $db->getResult();

    $arr3 is groving every query. But when only use $arr3 is more small value.

    why?

  • http://www.ameerpetstudent.com Billa Rajinikar Reddy Ameerpet

    Your article is very good

  • http://www.seowebengineers.com/ Sham Sehgal

    Hey man, its a nice post and is informative too, thanks a ton for that…. but there are too much conditions u applied on this code.. I think we can make it a bit easier by removing some conditions and other variables…. otherwise its a good post and I really appreciate your hard work…. :-)

    Thanks

  • http://brennannovak.com Brennan Novak

    This tutorial is terrible. The code in the tutorial is different than the code in the source files included. I’m sorry to be so negative but it’s just a bummer after going part by part writing the code trying to learn and then it not working. Then once trying with the source it works fine, they bug fixing to see where there are inconsistencies. Not sure why no body else has pointed this out….

  • Natalie Crowe

    Could you please fix the problems with the source code and your tutorial and resubmit. Having major issues here particularly with the update function.

  • mike

    Thank you so much for this tutorial. As a newbie to OOP I found easy to grasp what I think is a difficult area. There is lots on the web about OOP using php, but it’s so abstract and full of terms and definitions as to be confusing. There is nothing like a good, worked example. Well done, and thank you for oversimplifying it and leaving out such ‘essential’ topics such as ‘security’ which were not within the scope of this tuturial.

  • Pingback: Resources for PHP Webmail « David Woodfield

  • http://idiotsheep.com jabga

    insic is a very pretty woman. I am seeing him a long time.

  • http://www.coilplane.com Viktor Edholm

    I’m working on a class of my own and I’ve found a “flaw” in your code, in the update function. What if I want to use an OR instead of AND in the WHERE part?

  • lata

    where is The getResult() is in the source

  • http://jarodsworld.ismywebsite.com/ Jarod

    I cant get the update function to work right, mines suck -.-

  • Rami Reddy

    How set table name in place of $table , my table name is ‘moviebox’.

    Pls give me reply … Iam new to PHP OOPs

  • http://www.avlog.com.ar Pablo

    Excelent thnks a lot

  • bagas

    great tutorial

  • faisal

    where z getResult() method in the class??