Jump to content

Object Oriented PHP... first timer


DR4296
Go to solution Solved by gizmola,

Recommended Posts

Greetings All !

 

Just joined these forums / first time poster here.

 

I've been a PHP scripter for many years, but I've never really attempted to build something in an Object Oriented manner before.  (Oh, I took some classes in C# / .NET and have been doing some OO stuff with that, but it's all very simple and Visual Studio sets up the scaffolding for me.)

 

Anyways, I've been googling all day while working on building an app (actually a new version of an existing web site), trying to figure out how this all goes together.

 

So far, I've got a basic database library, an index.php page where I'm keeping the presentation ultra-simple for now... and then... a file "in the middle" where I've declared a couple of classes, plus their getters, setters, and constructors.

 

At this point, I started scratching my head a bit.  As I built each class, I basically gave it properties matching fields names on my tables.   So, I was thinking, how do I access those fields?

 

I found some examples that suggested I put methods within each of my key data structure classes themselves for doing this.   (Frankly, it didn't feel right, but I did it anyways.)

 

For instance, here's an abbreviated version:

class Incident_Row
{
   private $id;
   private $start_dt_tm;
   private $incident_type;

   public function get_id(){
       return $this->id;
   }
  public function set_id(){
       $this->id = $id;
  }

  // Pretend the other two getters and setters are here

  public function __construct($id=null, $start_dt_tm = null, $incident_type=null){
      $this->id = $id;
      $this->start_dt_tm = $start_dt_tm;
      $this->incident_type = $incident_type;
  }


function load($id){
   $oDB = new db();  // calls the db library / opens connection
   $obj = $oDB->fetch_one("SELECT id, start_dt_tm, incident_type from incidents WHERE id=$id");
   return $obj;
}

OK, so I just get this feeling I shouldn't be instantiating the database class right there in that "load" function.  Feels awkward / wrong.  Oh it work... UNLESS, on my index page, I try to call TWO similar functions within the same page.  Then it will do the first one... but upon the second attempt, it will give errors suggesting it has no idea what my database configuration info is.

 

 

I'll post some of my db library here:

class db
{
   public $dbh;

	// Create a database connection for use by all functions in this class
	function __construct(){
		
		require_once('db_config.php');
		
		if ($this->dbh = mysqli_connect($db_host, $db_user, $db_password, $db_name)){
		 
		 	// Set every possible option to utf-8
			mysqli_query($this->dbh, 'SET NAMES "utf8"');
			mysqli_query($this->dbh, 'SET CHARACTER SET "utf8"');
			mysqli_query($this->dbh, 'SET character_set_results = "utf8",'.
				'character_set_client = "utf8", character_set_connection = "utf8",'.
				'character_set_database = "utf8", character_set_server = "utf8"');	
		}else{
		 	$this->error = true;
		 	$this->error_msg = 'Unable to connect to MySQL.';
		 	$this->log_error('__construct', 'attempted connection to '. $db_name);
		}
		
	
	}
	
	function __destruct(){
		mysqli_close($this->dbh);
	}

	// Fetch a single row, return the object
  	public function fetch_one($query){
  	 	echo "DEBUG: query = $query<BR>";
  	 	$result = mysqli_query($this->dbh, $query);
		if ((!$row = mysqli_fetch_object($result))){
			return FALSE;
		}
		return $row;
	}
	
	public function fetch_all($query){
		echo "DEBUG: query = $query<BR>";
		$a = array();
		$result = mysqli_query($this->dbh, $query);
		while ($entry = mysqli_fetch_object($result)){
		 	echo "DEBUG: checking row....<BR>";
			$a[] = $entry;
		
		}
		if (empty($a)){
			return FALSE;
		}else{
		    var_dump($a);
			return $a;
		}
	}

}

(As you can see, I've got some debug statements and a var_dump in there.)

 

Note that if I change "require_once" to just "require" in the line up there, suddenly my index file IS able to do two functions similar to that "load" one in the same page... i.e. it will NOT behave like it doesn't know what the configuration info is.   This is why I really I don't think I should be instantiating the database class like that.

 

But, like I said, I've been googling all day, putting two and two together.  Seems like a lot of folks use PDO or some other similar class to pull objects out of the database.  But I wanted to do things slowly, in small steps, as I build this.. not slap in some other big library that I don't understand.

 

Can anybody give me some advice on what I'm doing wrong here?   Also, if you know of any tutorials where they not only show you classes and object-oriented design but also include how they get the data from the database all the way back through those classes / objects and to the presentation layer, I sure would like to see them!

 

Thanks!

 

-= Dave =-

 

Link to comment
Share on other sites

  • Solution

I would recommend looking at Dependency Injection to help with the decoupling. DI is an OOP design pattern popularized by OOP guru Martin Fowler, that's the foundation of Java frameworks like Spring, and in the PHP world Symfony2 and ZF2 to name just a few.

 

There's a great introduction in this series of articles by Symfony project founder Fabien Potencier.

 

 

In your case, you would pass your db object to the Incident_Row class in its constructor, rather than depending on a load() method to create it.

 

 

class Incident_Row
{
    private db;
    

    public function __construct($db)
    {
        $this->db = $db;
    }

Later when you create an Incident_Row object, you have a number of options ranging from creating the db class on the fly to using a global/registry/singleton db class.

 

$ir = new Incident_Row(new db());

// Or maybe an independent connection?

$db = new db();

$ir = Incident_Row($db);

This helps to keep specific db code out of the Incident_Row() class, although in this example, it's probably hard to see how that might be an advantage if you're calling class db specific methods inside Incident_Row(). If however, Incident_Row was written to a specific interface, you could derive a class from db() that wraps it, while implementing the interface.

 

In other words, you have to come up with a generic db api to call rather than using the mysql specific one. This is the approach taken with design patterns like ActiveRecord (Ruby on Rails) and PHP ORM's like Doctrine or Laravel Eloquent implement.

 

This would theoretically lead you to a point where you could interchange database connection objects and the Incident_Row class would work exactly the same way. So, for example, if you passed a Postgresql connection your code would still work. More practically, it makes it trivial to have code that is "environment" aware, so that you on setup configurations for each environment, and all the other code will work without issue.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.