Small Unit Raid (SUR) Small Unit Raid is based on the idea of performing operations against what would be called structures in C. Now before you say, "But PHP doesn't support struct or typedef!", realize that I know that and to get around it, I'm taking liberty with classes by defining them without methods. This may sound crazy, but a) the performance speaks for itself and b), the performance speaks for itself. The above said, with Small Unit Raid (SUR) there are no methods as such, but instead structures and associated functions designed specifically to operate against these structures. So, where an object, wich is essentially a structure with the additon of functions, may do something like... $query_obj->doQuery(); SUR would do something like... SUR_doQuery(&$query_struct); In other words, instead of the data structure (it can be argued that objects are the logical extensions of data structures) preforming an operation on itself (affecting it's own state), it's done from outside via a function. One thing that seperates structures from objects is the fact that an instance of the former can not affect changes upon it's own state. With that out of the way, the next question may be "what's the point?" Well, to that I say read the FAQ. I also mentioned it at the end of the first paragraph. Now let's talk about how to use it. Starting with the functions and naming conventions. A list of the functions is below. --> with dbStruct.php <-- SUR_setDbConn() SUR_doConnect() SUR_selectDb() SUR_disConnect() --> with queryStruct.php <-- SUR_setDbQuery() SUR_doQuery() SUR_getResult() SUR_getResultSet() SUR_getRowCount() SUR_getAffected() --> with proc_results.php <-- SUR_procResultSet() --> with db_functions.php <-- SUR_connectToDb() SUR_getData() SUR_putData() SUR_updateData() --> with transactions.php <-- SUR_dbBegin() SUR_doCommit() SUR_doRollback() The first thing that the observant will notice is that functions like SUR_getData() and SUR_putData() seem somewhat analogous to SUR_doQuery(). Well, as you'll see later, the functions that come in the db_functions.php file are for orchestration purposes and are not really needed at all. Another question may be "Why (not to mention what?) is the SUR_procResultSet() function in a file by itself?" This is becuase of how it is intended to be used. This will be touched upon later. The easiest way to use it (SUR) in a app may be to have a common config file and define some constants, not to mention including the files in the first place. # Create constants define("SUR_HOST", 'your db'); define("SUR_UNAME", 'your user name'); define("SUR_PASS", 'your password'); That done, to create the structures, just use the new statement as used for instantiating an object. $db_conn = new structDbConn; // A connection struct $db_query = new structDbQuery; // A query struct Now the absolute easiest way to use it is to employ those orchestration functions I mentioned earlier. SUR_connectToDb(&$db_conn) SUR_getData(&$SQL, 'name_of_db', &$db_conn, &$db_query) SUR_procResultSet(&$db_query) First, it's assumed that you've created the query represented above by $SQL. Also, if a db has allready been selected, then the second argument can be ''. Why do a select db again right? In most cases, the above is enough for getting information out to a page. Let's take a closer look at what just happened. Essentaily, the three functions above are each calling multiple other functions to get the job done in the backgound. Here is the breakdown. SUR_connectToDb(&$db_conn) | | |__SUR_setDbConn() SUR_doConnect() SUR_getData(&$SQL, 'name_of_db', &$db_conn, &$db_query) | | |__SUR_selectDb() (if needed) SUR_setDbQuery() SUR_doQuery() SUR_procResultSet(&$db_query) | | |__your_process_row_function() (or functions) Do you see the point now of the above functions. You could alternately do the below. SUR_setDbConn() SUR_doConnect() SUR_selectDb() SUR_setDbQuery() SUR_doQuery() while(SUR_getResultSet()) { your_process_row_function() (or functions) } Please note that with appropriate error checking for these examples, they get alot dirtier. Anyway, here is an example using the orchestration functions. This is based on the benchmark test included with the download. The timing code and other pertinent comments have been removed. # Create Structures. $db_conn = new structDbConn; // The connection struct $db_query = new structDbQuery; // The query struct if(!SUR_connectToDb(&$db_conn, 'db')) // Connect or do error stuff { echo $db_conn->error."\n"; exit; } $SQL="SELECT foo FROM bar LIMIT 0, 100"; // A select if(SUR_getData(&$SQL, '', &$db_conn, &$db_query)==true) { SUR_procResultSet(&$db_query); } // Result set processed here else { echo $db_query->error."\n"; break; } // Error handling would go here SUR_disConnect(&$db_conn); // Close connection # A test processing function function display_info($row) { echo "$row[0]\n"; } A couple of things to note about the above. Errors are written to the error element of the structures. $db_query->error as an example. If there is an error with a query, it'll be written there. One can use error handling functions or whatever to deal with it. Echoing the errors out to the screen is only good for debugging and demonstration as above. This isn't a Small Unit Raid "modus operandi". Also, the function display_info() is tucked away in the SUR_procResultSet() function which is included (or required). That file with the function added looks like the below. ################################################################################### # Return results to the user function SUR_procResultSet($struct, $how='') { switch($how) { case('i'): // To grab as a numeric array { while($row=mysql_fetch_row($struct->resource)) { /* Process row here */ } break; } case('a'): // As an associative array { while($row=mysql_fetch_assoc($struct->resource)) { /* Process row here */ } break; } default: // To get both { while($row=mysql_fetch_array($struct->resource)) { display_info($row); } } } } # End SUR_procResulSet() ################################################################################### OK. The particulars about the above are: 1) The function (or functions) for processing the rows returned from the result set are actually called here. 2) There are three options on how to return result sets. You need to place your row processing functions in the correct place based on how you want the info returned. In this example, we are using the default which employs mysql_fetch_array(). 3) Execution will remain in this function until all rows have been processed, unless one of the row processing functions exits or does some other way out operation. 4) Objects may be called as well as functions. For example: case('a'): // As an associative array { while($row=mysql_fetch_assoc($struct->resource)) { $display_obj->show_rows($row); } break; } The drawback to this approach being that at the entry to the function, the object(s) need to be declared global. Another, and perhaps better option is to use the $GLOBALS array. Therefore, the above would look like... case('a'): // As an associative array { while($row=mysql_fetch_assoc($struct->resource)) { $GLOBALS['display_obj']->show_rows($row); } break; } At least this way, the function doesn't need to be hacked apart to accept multiple args, nor is there a need to use the global command for each object. Also, the use of the $GLOBALS array in this manner is, to the best of my knowledge, not widespread. That said, make sure you pass the name of the object as an array element without the '$'. Note the example. Some may not agree with the use of objects to output data, or even functions. That's fine. I'm just showing some options. Beyond this, to each their own. Going back, the reason this function is in a file by itself is because it should to used as a template. Not all of your pages are going to retrieve and format the data in the same manner. In this way, you simply copy the original (as though it is a template) and dump in the appropriate functions. Once that's done, you can either include it or place it directly in the main script. The biggest reason for taking this approach is speed. I first started experimenting with this approach when messing around with the dbx functions. The benchmarks show that using the approach is a little faster than just calling the plain mysql functions. I have no idea why! I just know what the results of the benchmarks say. Take a close look at some of the commented out sections of code in the included bench.php file and you can see where I tried a more standard approach as well as using SUR_procResultSet(). It should be noted however, that in most real world applications, not too many results are going to be returned or displayed. Keeping that in mind, a more standard approach isn't noticeable slower than just using mysql function calls. However, as the result set grows, so does the disparity in performance. An example of more standard usage would be... while($row=SUR_getResultSet()) { your_process_row_function($row) (or functions) } My suspicion was (and still is) that each call to SUR_getResultSet() was the problem. In particular, the fuction having to deal with the passed arguments. However, other tests seem to disprove this. I'm really not sure when you get right down to it. Here is an example of some of the runs. Results for straight mysql operations at 100K lines. This is using mysql_fetch_array 1 3.142 1 3.296 2 * 3.221 2 3.116 3 3.131 3 3.220 4 3.111 4 3.234 5 3.151 5 3.294 6 3.179 6 * 3.354 7 * 3.339 7 * 3.314 8 3.148 8 3.238 9 * 3.175 9 * 3.308 10 3.144 10 3.299 Results for Small Unit Raid at 100K lines. This is using mysql_fetch_array 1 2.918 1 2.956 2 * 3.435 2 2.893 3 * 3.032 3 * 3.003 4 2.989 4 2.986 5 2.990 5 2.963 6 2.896 6 2.912 7 2.988 7 2.950 8 2.920 8 2.903 9 * 3.082 9 * 3.005 10 3.032 10 * 3.060 The stars represent scores that I was going to throw out. I was then going to come up with an average of the remaining results. This was foundation work for a story I was going to write. As you can see, SUR scored better than just using MySQL function calls. Honestly, I STILL don't believe it, but there it is just the same. If anybody can show me where I can tweak the benchmark for using straigh mysql function calls, I'm all ears as I don't wish to mis-represent anything. OK. The easy way is now out of the way. The hard way involves calling each of these functions individually. I'm assuming that those of us with experience pulling data from a db can figure out the order that these functions will need to be called in, so I'll focus on just the functions in dbStruct.php, queryStruct.php, and transactions.php. First things first, here is a Small Unit Raid maxim. ALL(!) structs shall be passed by reference! Things won't work otherwise. SUR_setDbConn($struct, $host, $user='', $pass='', $db='') This sets up the structure. You could say it populates it with data. $strcuct is the db structure. The rest are easy to figure out, I think. SUR_doConnect($struct) Connects to the db using the passed db structure. SUR_selectDb($struct, $db) Selects a database to work with using the passed db structure. SUR_disConnect($struct) Closes a connection using the passed db structure. SUR_setDbQuery($struct, $conn='', $query='') Sets up the query structure. Note we are now talking about the query as opposed to db structure. Note also that $conn and $query are optional SUR_doQuery($struct) Obvious. Of course, it's using the passed query structure. SUR_getResult($struct, $arg) If you are only looking for one result, as opposed to rows and rows, this makes more sense. SUR_getResultSet($struct, $how='') For fetching rows of data from a result set. The struct is the passed query struct. $how is 'i' for a numeric array and 'a' for an associative. If this arg isn't included, the function returns both leaving it up to you to sort it out. SUR_getRowCount($struct) Return the number of rows in a result set. SUR_getAffected($struct) Returns the number of affected rows from an update, delete, or insert. SUR_doBEGIN($struct, $conn) This is to start a transaction. The $struct argument is the query structure and the $conn arg is the db structure. SUR_doCOMMIT($struct, $conn) To commit a transaction. The args are the same as above. SUR_doROLLBACK($struct, $conn) To rollback a series or queries. The args are the same as above. I think that's it. If there is anything amiss or unclear about the above, let me know. I'm just some galoot that likes to mess around with stuff so I'm bound to have messed up something. Now go forth and have fun. Cheers, BDKR (Terrence Cox)