/code/blog

Code, code and code

Functional Programming in PHP

Was recently brave (or foolhardy) enough to attempt to present how functional programming constructs could be used even in a language such as PHP. Now I am fully aware that one of the bigger reasons for functional programming ie. concurrency is simply not applicable as yet for a language like PHP, but I thought it might still be useful to reduce global variable proliferation, and improve both composability and testability. The following sample PHP code was what I presented. The associated Twig template is not shown since it is not particularly relevant to the context. Note that the following is simply a sample code - any attempts to use it are at your own risk - I am simply not a good enough PHP programmer to even know if the code is good or has many smells that are entirely invisible (or unodorous) to me. The code simply retrieves data from a table, filters it and shows it on screen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?php
 require_once 'Twig/Autoloader.php';
 Twig_Autoloader::register();

##### Global constants #####
$base='\/funcblog';

function initialise()
{
	##### Environment #####
	$loader = new Twig_Loader_Filesystem('templates');
	$twig = new Twig_Environment($loader, array(
	  'debug' => true,
	  'cache' => 'cache',
	));
	
	
	#### Database initialisation #####
	
	$link = mysql_connect('localhost', 'funcblog', 'funcblog')
	    or die('Could not connect: ' . mysql_error());
	mysql_select_db('funcblog',$link);
	return array('twig' => $twig, 'link' => $link);
}

##### Application configuration #####
$routes = array(
	array(path=>'posts',handler=>'get_posts'),
	array(path=>'categories',handler => 'get_categories')
	);

// Initialise the route map based on the routes configuration
$route_map = array_reduce(
		$routes,
		function ($x,$y) { $x[$y['path']] = $y['handler']; return $x;},	
		array());

##### Functions #####

// Extract path and request components from URI
function compose_request($request_uri,$base)
{
	preg_match_all('/('. $base . ')(?P<path>(\/\w+)+)(\?(?P<query>(\w+=[^\&]+\&?)*))?/', $request_uri, $words, PREG_SET_ORDER);
	return array($words[0]['path'], $words[0]['query']);
}

// process the uri based on path and query options
function process_uri($context, $route_map, $path,$query)
{
	$handler_name = $route_map[ltrim($path,'/')];
	return $handler_name($context, $query);
}

// Display the template with the associated data
function display_template($context,$template,$data)
{
	$context['twig']->loadTemplate($template)->display($data);
}

$context = initialise();

// Closure to extract rows from table
$context['get_rows'] = function ($query) use($context)
{
	$result = mysql_query($query,$context['link']);
	$rows = array();
	while ($row = mysql_fetch_assoc($result))
	{
		$rows[] = $row;
	}
	return $rows;
};

// From the request URI, extract the path and the query parameters
list($path, $query) = compose_request($_SERVER['REQUEST_URI'],$base);

// Dispatch to the appropriate function based on the uri to routes mapping
list($template, $data) = process_uri($context, $route_map,$path,$query);

// Display the template
display_template($context,$template,$data);

##### Custom Application Logic #####

function get_posts($context,$query)
{
	# NOTE : An Array filter function, filters a collection using a
	#        filter function. It returns a subset of that collection
	#        for which the filter function (predicate) evaluates to true
	$posts = array_filter(
		$context['get_rows']('select * from posts'),
		function($row) {
			return ($row['author'] == 'dhananjay') ;
		}
	);
	return array('posts.html', array('rows'=> $posts));	
}
?> 

Comments