In terms of a real-world example of what goes in these 4 different layers, assume we
are writing a database-backed application that needs to fetch a user record containing
various fields. This is a very common thing to do in a web app. Our template layer
might look something like this:
php.ini
auto_prepend_file = "./helpers.inc"
include_path = "/usr/local/lib/php"
Template Layer
<?title('Example Page')?>
<?greeting()?>
<h1>Heading 1</h1>
<p>
Page content
</p>
<h1>Heading 2</h1>
<p>
Yada Yada
</p>
<h1>Heading 3</h1>
<p>
Page content
</p>
<?footer()?>
Template Helpers
<?php
include "logic.inc";
echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en" lang="en">
<?php
$user = get_user_record($_COOKIE['user_id']);
function greeting() {
global $user;
echo "Hi " .$user['first_name'] ."!<br />\n";
if($age=birthday($user)) {
echo "Congratulations, today is your ";
echo "$age birthday!<br />\n";
}
}
function title($title) {
echo "<head><title>$title</title></head>\n";
echo "<body>\n";
}
function footer() {
echo "</body>\n</html>";
}
?>
Business Logic
<?php
function get_user_record($id) {
mysql_connect('localhost');
mysql_select_db('users');
$res = mysql_query("select * from users where id='$id'");
if(!$res) echo mysql_error();
else $row = mysql_fetch_array($res);
return $row;
}
function birthday($user) {
if(strftime('%m %d')==strftime('%m %d',$user['bday']))
$age = strftime('%Y') - strftime('%Y',$user['bday']);
if(($age%100)>10 && ($age%100)<20) $ap='th';
else switch($age%10) {
case 1: $ap = 'st'; break;
case 2: $ap = 'nd'; break;
case 3: $ap = 'rd'; break;
default: $ap = 'th'; break;
}
return $age.$ap;
else
return false;
}
?>
In this case the final layer written in C contains the mysql_* functions, and the date()
function. These happen to be standard PHP functions. If birthday() is called many times on
every single request and since how you figure out if it is someone's birthday is unlikely
to change very often, this may be a good candidate to translate into C. Although, in this
example, the birthday function is probably too simple to see much of a performance improvement.
On the other hand, other than a little bit of added parameter parsing, if you compare the C
version of birthday() to the PHP version, it isn't that much harder to write it in C.
C Layer
PHP_FUNCTION(birthday)
{
time_t timestamp, now;
struct tm *ta1, tmbuf1, *ta2, tmbuf2;
int age;
char ret_age[8];
if (zend_parse_parameters(1 TSRMLS_CC, "l", ×tamp) == FAILURE)
return;
ta1 = php_localtime_r(×tamp, &tmbuf1);
time(&now);
ta2 = php_localtime_r(&now, &tmbuf2);
if(tmbuf1.tm_mday==tmbuf2.tm_mday && tmbuf1.tm_mon==tmbuf2.tm_mon) {
age = tmbuf2.tm_year - tmbuf1.tm_year;
if((age%100)>10 && (age%100)<19) sprintf(ret_age,"%dth",age);
else switch(age % 10) {
case 1: sprintf(ret_age,"%dst",age); break;
case 2: sprintf(ret_age,"%dnd",age); break;
case 3: sprintf(ret_age,"%drd",age); break;
default:sprintf(ret_age,"%dth",age); break;
}
} else {
RETURN_FALSE;
}
RETURN_STRING(ret_age,1);
}