eldan88 Posted October 27, 2013 Share Posted October 27, 2013 Hey Guys. Quick question about using affected_rows OOP style. When I define the following method: public function affected_rows() { return $this->_connection->affected_rows; } in my MySQLDatabase class and call it from a different class it displays the affected rows. Want I want is to call affected rows from the MySQLDatabase with out having a method in it. I want to use what mysqli returned back to me. Is there anyway where I can do that? Below is the following code I am using to call the affected rows from the other classes... Thanks for your help in advance public function update($table_name, $attributes,$id) { global $database; $attribute_pairs = array(); foreach($attributes as $key => $value) { $attribute_pairs[] = "{$key}='{$value}'"; } $sql = "UPDATE {$table_name} SET "; $sql .= join(", ", $attribute_pairs); $sql .= "WHERE id = {$id} "; $result = $database->query($sql); return $result->affected_rows == 1 ? true : false; Below is my whole MySQLDatabase class ($database) <?php require('config.php'); class MySQLDatabase { private $_connection; public $last_query; private $magic_quotes_active; private $real_escape_string_exists; public function __construct() { //$this->_connection = new mysqli($host, $user, $password, $database, $port, $socket) $this->_connection = new mysqli('localhost', 'root'); if(!$this->_connection) {die('Connection Error'.$_connection->connect_error ); } else { $db_select = $this->_connection->select_db(DB_NAME); } if(!$db_select) { die("Database Selection Failed" . $this->_connection->error); } $this->magic_quotes_active = get_magic_quotes_gpc(); $this->real_escape_string_exists = function_exists( "mysql_real_escape_string" ); } public function query($sql) { $this->last_query = $sql; $result = $this->_connection->query($sql); $this->confirm_query($result); return $result; } //Database Nuteral Methods private function confirm_query($result){ if(!$result) { $output = "Database query failed: "; $output .= "Last query ". $this->last_query; die($output); } } public function num_rows($result_set) { $this->_connection->num_rows($result_set); } public function insert_id() { //Get the last ID inserted over the database return $this->_connection->insert_id(); } public function affected_rows() { return $this->_connection->affected_rows; } //Database Netural Methods public function __clone(){} public function escape_value( $value ) { if( $this->real_escape_string_exists) { // PHP v4.3.0 or higher // undo any magic quote effects so mysql_real_escape_string can do the work if( $this->magic_quotes_active ) { $value = stripslashes( $value ); } $value = mysql_real_escape_string( $value ); } else { // before PHP v4.3.0 // if magic quotes aren't already on then add slashes manually if( !$this->magic_quotes_active ) { $value = addslashes( $value ); } // if magic quotes are active, then the slashes already exist } return $value; } public function close_connection(){ if(isset($this->_connection)) { $this->_connection->close(); unset($this->_connection); } } }//end of class $database = new MySQLDatabase(); ?> Quote Link to comment Share on other sites More sharing options...
trq Posted October 27, 2013 Share Posted October 27, 2013 You could make your query() method check the $sql it is processing to see if it is a SELECT, DELETE or UPDATE query. When its a DELETE or UPDATE return the number of rows affected else, if a SELECT, return the result set. Quote Link to comment Share on other sites More sharing options...
eldan88 Posted October 27, 2013 Author Share Posted October 27, 2013 trq. Thanks for the reply... How do I do that? Quote Link to comment Share on other sites More sharing options...
mac_gyver Posted October 27, 2013 Share Posted October 27, 2013 $database is an instance of your database class. $database is not an instance of the mysqli database class. the instance of your database class only holds an instance of the mysqli database class in the _connection private property. for the affected_rows() method, it must have the actual database connection as part of it. the only place your actual mysqli database instance/connection is at is in the _connection private property in the instance or your database class. the code that runs must eventually result in $this->_connection->affected_rows. to do that, you must provide a method in your database class. your current code of return $result->affected_rows == 1 ? true : false; won't work correctly. $result is either a true or a false for an UPDATE query and that code should be producing a Notice: message about trying to get a property of a non-object. you need to stop using the global keyword to being the instance of your database class it into your other classes. didn't you fix this by brining it into the classes as a call time parameter when you created the instance of your classes? Quote Link to comment Share on other sites More sharing options...
objnoob Posted October 27, 2013 Share Posted October 27, 2013 $sql = "UPDATE ...."; # an SQL statement that updates data in the database $result = $database->query($sql); return ( $result && $database->affected_rows) ? true : false; Quote Link to comment Share on other sites More sharing options...
objnoob Posted October 27, 2013 Share Posted October 27, 2013 (edited) You could create some additional methods in your database class... class myDatabaseClass { public function query($columns, $table_name, $where = null){ } public function update($columns, $table_name, $where = null){ $list = array(); foreach($columns as $col=>$val) $list[] = $col . '=' . $this->_connection->real_escape_string($val); $sql = 'UPDATE ' . $table_name . ' ' . implode(',', $list) . ' ' . $where; if($this->_connection->query($sql) === false) return false; else return $this->_connection->affected_rows; } } Edited October 27, 2013 by objnoob Quote Link to comment Share on other sites More sharing options...
eldan88 Posted October 28, 2013 Author Share Posted October 28, 2013 mac_gyver. Thanks for the reply. I changed the code by adding the following method in my database class public function affected_rows() { return $this->_connection->affected_rows; } Then I changed the following on my other class that has the update method public function affected_rows() { return $this->_connection->affected_rows; } Does this looks correct? Also I don't know what you mean by "didn't you fix this by brining it into the classes as a call time parameter when you created the instance of your classes?" Please explain. Thanks Quote Link to comment Share on other sites More sharing options...
eldan88 Posted October 28, 2013 Author Share Posted October 28, 2013 objnoob. Thanks for the reply. But the code didn't work Quote Link to comment Share on other sites More sharing options...
objnoob Posted October 28, 2013 Share Posted October 28, 2013 (edited) Adding this method to your custom Database class is silly. public function affected_rows() { return $this->_connection->affected_rows; } If your custom database class had query, update, delete methods. The update and delete methods would return the affected rows count, otherwise false. This kills two birds with 1 stone! See this example: class myDatabaseClass { public $this->_connection; public function __construct(mysqli $database){ $this->_connection = $database; } public function update($columns, $table_name, $where = null){ $list = array(); foreach($columns as $col=>$val) $list[] = $col . '=\'' . $this->_connection->real_escape_string($val) . '\''; $sql = 'UPDATE ' . $table_name . ' ' . implode(',', $list) . ' ' . $where; if($this->_connection->query($sql) === false) return false; else return $this->_connection->affected_rows; } } Edited October 28, 2013 by objnoob Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted October 28, 2013 Share Posted October 28, 2013 mac_gyver. Thanks for the reply. I changed the code by adding the following method in my database class public function affected_rows() { return $this->_connection->affected_rows; } Then I changed the following on my other class that has the update method public function affected_rows() { return $this->_connection->affected_rows; } Does this looks correct? Also I don't know what you mean by "didn't you fix this by brining it into the classes as a call time parameter when you created the instance of your classes?" Please explain. Thanks He means that you need to remove 'global' and instead pass in the database as an argument in your constructor. More to the point, never, ever, EVER use 'global'. I know that Lynda and other tutorials use it, but it's bad practice, especially in an OOP context. You need to forget you ever saw it. Quote Link to comment Share on other sites More sharing options...
objnoob Posted October 28, 2013 Share Posted October 28, 2013 It's called dependency injection! Google dependency injection and learn all about it! Quote Link to comment Share on other sites More sharing options...
eldan88 Posted October 29, 2013 Author Share Posted October 29, 2013 Kevin. I am a little confused on how to accomplish this. Is this similar to that object composition I did previously? Quote Link to comment Share on other sites More sharing options...
eldan88 Posted October 29, 2013 Author Share Posted October 29, 2013 Lets say I want to use "dependency injection" for my MySQLDatabase class... Do i do it like this? public function __construct() { $database = new MySQLDatabase(); } Quote Link to comment Share on other sites More sharing options...
KevinM1 Posted October 29, 2013 Share Posted October 29, 2013 Lets say I want to use "dependency injection" for my MySQLDatabase class... Do i do it like this? public function __construct() { $database = new MySQLDatabase(); } No, you need to pass in a database object as an argument to your constructor: class MyObject { private $db; public function __construct($db) { $this->db = $db; } // other class stuff } $database = new MySQLDatabase(); $myObj = new MyObject($database); Functions and methods have several parts to them: 1. Their name 2. Their argument list 3. Their return type(s) Put all together, they represent that function's or method's signature. That signature is important, because it tells you how that function/method works at a glance. More importantly, it infers a kind of contract between it and the rest of your code. "I will only work if you call me by name, pass in these kinds of values. In return, I'll give you this other kind of value." Functions/methods are supposed to be black boxes to the code that invokes them. 'global' breaks that contract by introducing an implicit requirement, one that doesn't follow the normal rules of scoping. In order for a function/method with 'global' to work correctly, the code that invokes the function/method needs to know of that hidden requirement. That makes them not black boxes, and instead leads to hard-to-change spaghetti code. Since functions and, even more to the point, OOP are all about reusability and modularity, you're writing code that undoes the entire point of it all. So, 'global' is bad no matter how you slice it. Any resource that uses 'global' in its code should be considered a bad resource. --- With dependency injection, you're simply composing objects at construction time (usually). If an object requires another object to work, simply make that dependency a member of the object that uses it. You get all the benefits and none of the restrictions of inheritance or (even worse) singletons (which are a special form of globals, and should be avoided at all costs). Your code will be easier to maintain. Quote Link to comment Share on other sites More sharing options...
eldan88 Posted November 9, 2013 Author Share Posted November 9, 2013 Thanks for that explanation Kevin 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.