PHP Objects, Patterns and Practice (3rd edition)

(Barry) #1

CHAPTER 11 ■ PERFORMING AND REPRESENTING TASKS


Of course, you have a programming language at hand right away. It’s called PHP. Here’s how you
could allow your users to script your system:


$form_input = $_REQUEST['form_input'];
// contains: "print file_get_contents('/etc/passwd');"
eval( $form_input );


This approach to making an application scriptable is clearly insane. Just in case the reasons are not
blatantly obvious, they boil down to two issues: security and complexity. The security issue is well
addressed in the example. By allowing users to execute PHP via your script, you are effectively giving them
access to the server the script runs on. The complexity issue is just as big a drawback. No matter how clear
your code is, the average user is unlikely to extend it easily and certainly not from the browser window.
A minilanguage, though, can address both these problems. You can design flexibility into the
language, reduce the possibility that the user can do damage, and keep things focused.
Imagine an application for authoring quizzes. Producers design questions and establish rules for
marking the answers submitted by contestants. It is a requirement that quizzes must be marked without
human intervention, even though some answers can be typed into a text field by users.
Here’s a question:


How many members in the Design Patterns gang?


You can accept “four” or “4” as correct answers. You might create a web interface that allows a
producer to use regular expression for marking responses:


^4|four$


Most producers are not hired for their knowledge of regular expressions, however. To make
everyone’s life easier, you might implement a more user-friendly mechanism for marking responses:


$input equals "4" or $input equals "four"


You propose a language that supports variables, an operator called equals and Boolean logic (or and
and). Programmers love naming things, so let’s call it MarkLogic. It should be easy to extend, as you
envisage lots of requests for richer features. Let’s leave aside the issue of parsing input for now and
concentrate on a mechanism for plugging these elements together at runtime to produce an answer.
This, as you might expect, is where the Interpreter pattern comes in.


Implementation


A language is made up of expressions (that is, things that resolve to a value). As you can see in Table 11–1,
even a tiny language like MarkLogic needs to keep track of a lot of elements.


Table 11–1. Elements of the MarkLogic Grammar


Description EBNF Name Class Name Example

Variable variable VariableExpression $input
String literal <stringLiteral> LiteralExpression "four"

Boolean and indexer BooleanAndExpression -$input equals '4' and
$other equals '6'
Boolean or orExpr BooleanOrExpression -$input equals '4' or
$other equals '6'
Equality test equalsExpr EqualsExpression $input equals '4'
Free download pdf