DR4296 Posted February 25, 2014 Share Posted February 25, 2014 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 =- Quote Link to comment Share on other sites More sharing options...
Solution gizmola Posted February 25, 2014 Solution Share Posted February 25, 2014 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. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.