Simple Stored Procedure Emulation with PHP/mySQL
April 10th, 2002My “third time, automate” rule came in handy again recently. I’m doing all sorts of PHP/mySQL work and I found myself hacking together the same SQL queries over and over with just some different filter or sort order. Being used to stored procedures, I was missing the easier syntax.
Here’s what I came up with….
rather than:
sql = "select height, name from students where height>$minHeight order by $orderCol";
I wanted to say something more along the lines of:
getStudentsByHeight( minHeight, order );
Of course, I could wrap every such query in a PHP function, but I wanted to make it feel more like a stored procedure.
So, I created a procs table in my database:
CREATE TABLE procs ( name varchar(50), description text, sqltext text, )
Then I created a record:
name: getStudentsByHeight description: getStudentsByHeight( minHeight [in cm] , order [by 1=height or 2=name]) sqltext: select height, name from students where height>$1 order by $2
And then I created a function I called sproc(). This function takes the name of a procedure, and its parameters in an array, so you can call it like this:
sql = sproc( 'getStudentsByHeight', array( 150, 2 ) );
sproc() iterates through the parameters and does a string replacement on the sql text for each. Then it returns the sql.
function sproc($proc,$parms){ $sql="select sqltext from procs where name='$proc'"; $rs=mysql_query($sql); if (mysql_num_rows($rs)>0){ $row = mysql_fetch_row($rs); $sqlText = $row[0]; if(isset($parms)){ if(is_array($parms)){ for($i=0;$i<count($parms);$i++){ $sqlText=str_replace('$'.($i+1),$parms[$i],$sqlText); } }else{ $sqlText=str_replace('$1',$parms,$sqlText); } } return $sqlText; }else{ print "<div>procedure [$proc] does not exist</div>"; exit(); } }
Now when I want to change the sql to include more fields and therefore more ordering choices, I only have to change it in the database, without ever touching the code!
select height, name, shoesize from students where height>$1 order by $2
Of course, since you’d have to redo your display for the extra field, it’s not complete without a generic table building function. That brings the entire table generation code to this line:
print tblFromRS(mysql_query(sproc('getStudentsByHeight',array(150,2))));
function tblFromRS($rs){ $s="<table border="1"><tr>"; while($fld = mysql_fetch_field($rs))$s.="<th>$fld->name</th>"; $s.="</tr>\n"; while($row = mysql_fetch_row($rs)){ $s.="<tr>"; for($i=0;$i<mysql_num_fields($rs);$i++)$s.="<td>$row[$i] </td>"; $s.="</tr>\n"; } $s.="</table>\n"; return $s; }
Now I can manage my sql queries all in the database. On any new project, I just bring across the generic functions and the procs table and off I go.
It’s no replacement for real stored procedures, but it’s a good stopgap.
cool idea man. One thing: it looks like you’d be doing twice the queries this way. Maybe you could have some sort of caching function where it dumps the procs table to a .php file as some multi-dimensional array:
$res = mysql_query(“SELECT * FROM procs;”);
while($row = mysql_fetch_array($res)) {
$name = $row[name];
$procs[$name] = array(
‘description’=>$row[description],
‘sqltext’=>$row[sqltext]
);
}
Then, you could change the first line of the sproc() function:
function sproc($proc,$parms){
$sql=”select sqltext from procs where name=’$proc'”;
TO
function sproc($proc,$parms) {
$sql=$GLOBALS[‘procs’][$proc][sql];
maybe i’m a bit anal about caching and all that…
by rick April 10th, 2002 at 3:36 amThat’s a good idea. I wasn’t thinking of efficiency as much as my code maintainability. It’s all me, me, me, isn’t it!
There’s a few places one could go with this. It’s just a germ of an idea, really.
by brentashley April 10th, 2002 at 8:21 amSo Brent.. when are you going to update this to make use of caching, etc? It would be quite handy 🙂
by Rick September 16th, 2003 at 8:47 pmOr I could just use the one outlined above 🙂 It would just be interesting to see how far we could take this.. or just wait for stored procedures in MySQL 🙂
by Rick September 18th, 2003 at 12:34 amBrent….why be such a slacker?
by ellisdhea February 15th, 2005 at 12:55 pmEvan – slacking is one of the prime motives of the hacker ethic!
by brent February 15th, 2005 at 1:00 pmHi…
Question.
I just don’t get the Caching stuff.
i’d like to do this
a stored procedure doing:
“Select * from TableX”
All of it’s information would be saved in Cache, And, calling it, i would pass some
constrains like:
“where id = @User_id”
by Rochon March 23rd, 2005 at 2:03 pm