An expression is the part of a tag that works out a value: 1 + 2,
$price * $qty, $name | upper, $state in ('open',
'pending'). PAD's evaluator reads it - numbers, strings, fields, lists, operators,
functions and pipes - and answers one value. This page goes through all of it; every example
is live, its template beside what PAD made of it.
An expression is read wherever a tag takes a value: the parameter of {echo} and of
{if} and {elseif}, the right side of
{set $x = ...}, the value of {case} and its
{when}s, the condition of {while} and
{until}, a quoted option such as where='...', and an
occurrence assignment %name = ... on a tag that loops:
|
PHP |
HTML fragments/expressions_1.pad |
Result |
|---|---|---|
|
Total: 37.5 Free shipping |
|
PHP |
HTML fragments/expressions_2.pad |
Result |
|---|---|---|
|
pen: 12 in stock, order 8 pad: 5 in stock, order 15 |
|
PHP |
HTML fragments/expressions_3.pad |
Result |
|---|---|---|
|
7 is odd 1 2 4 8 16 |
A field tag takes a pipe as it stands - {$name | trim} - and so
does the closing tag of a pair, over everything the pair rendered. The
pipes page has the opening and closing tag pipes in full:
|
PHP |
HTML fragments/expressions_4.pad |
Result |
|---|---|---|
|
Ada Lovelace PHP SQL PAD |
Whole numbers, decimals, a decimal that starts with its point (.5) and
exponents (1e3, 2.5E-1). A minus before a number belongs to it.
0x followed by hexadecimal digits is not a number but a string of bytes:
0x41 is the letter A.
| HTML | RESULT |
|---|---|
| 42 |
| -5 |
| 5 |
| 0.75 |
| 1001 |
| 1 |
| A |
| PAD |
Text stands between single or double quotes, which mean the same: a $name
inside double quotes stays text, it is not filled in as PHP would. A backslash starts an
escape - \n, \r, \t, \\,
\' and \"; any other letter after it is an error. The dot joins
strings, and numbers with them:
| HTML | RESULT |
|---|---|
| single quotes |
| double quotes |
| it's |
| say "hi" |
| back\slash |
| one |
| 3 |
| Order 42! |
A word without quotes and without a sigil is looked up. An operator word -
eq, and, not ... - is the operator; a PHP constant -
TRUE, FALSE, NULL, PHP_EOL,
M_PI - is its value; a word that names nothing stands for its own text.
| HTML | RESULT |
|---|---|
| 1 |
| [] [] |
| 8 |
| 3.1416 |
| hello |
| 1 |
Quote text. A bare word that names something PAD knows - a function, a tag, a
property, a data set, a field - is that thing: count, name and
first are properties, so
{echo count} does not write the word count. Text in quotes is always
text.
$name reads a field: a variable the page's PHP set, one a
{set} made, a field of the row a loop stands on. A dot walks into an
array - $user.address.city, and $items.0 by position.
|
PHP fragments/expressions_8.php |
HTML fragments/expressions_8.pad |
Result |
|---|---|---|
|
|
Ada from London PHP and PAD LONDON, W1 |
$$name reads the field whose name another field holds - a path as well - the
way {$$name} does as a tag. The name must be one of the application's
fields; the engine's own pad... variables are never read this way.
|
PHP fragments/expressions_9.php |
HTML fragments/expressions_9.pad |
Result |
|---|---|---|
|
|
Hallo, Ada London |
A field that holds a list is not a value: $items + 1 is an error. Walk the
list with a loop, or hand it to a function with the array: prefix, below.
#name - a parameter or option of the tag; in a
{define} or a custom tag, the ones the tag was called with&name - a property of the tag, name@tag a property of the
tag named - first@items, current@items, count@items
(see properties)@ - the value piped into this part of the expression (see
pipes below)|
PHP |
HTML fragments/expressions_10.pad |
Result |
|---|---|---|
|
121.00 and 109.00 1 of 3: plan 2 of 3: build 3 of 3: ship - the last one |
[ ] makes a list, its items separated by commas, with keys written
key => value where wanted, mixed with plain items as PHP mixes them. A list is
what {set} stores, what a loop walks and what a PHP function
takes:
|
PHP |
HTML fragments/expressions_11.pad |
Result |
|---|---|---|
|
Minutes: 240 pages 2 3 5 7 1 + 2 + 3 = 6 |
A prefix says what a name is, so nothing else of that name can be meant:
field:, array: (a list as a value), data: (a
{data} set), constant:, php: (a PHP
function), pad: and app: (a built-in or an application pipe
function), function:, tag: and the others the
prefix page lists:
|
PHP |
HTML fragments/expressions_12.pad |
Result |
|---|---|---|
|
8 3 3 numbers, together 27 ===== PREFIXES |
The operators bind in this order, strongest first. Those of one row bind equally and are
applied left to right - 10 - 2 + 3 is 11 - except **, which binds
right to left. Round brackets group as usual.
| operators | what they do |
|---|---|
** | power, right to left: 2 ** 3 ** 2 is 2 ** 9 |
!, a sign - + before a value | not, and the signs - weaker than **: -3 ** 2 is -9 |
* / % | multiply, divide, remainder |
+ - | add, subtract |
. | join as text |
lt le gt ge - < <= > >= | order |
eq ne - == = != <> | equal, not equal |
not | denies what follows, a comparison included |
and - && | both hold |
xor | exactly one holds |
or - || | either holds |
?? | the left side, or the right one when the left is empty or missing |
? : and ?: | the inline ternary, weakest of all |
The tests in, like, matches, range,
between and contains read infix as well; they have
a section of their own.
As in PHP: / answers a decimal when it does not divide evenly, %
works on whole numbers. A text that is a number counts as one - '5' + '5' is 10 -
a text that is not, 'a' + 1, is an error, and so is a division by zero.
| HTML | RESULT |
|---|---|
| 10 |
| 4 |
| 21 |
| 3.5 |
| 1 |
| 1024 |
| -5 |
| 3.3333333333333 |
| HTML | RESULT |
|---|---|
| 7 |
| 9 |
| 11 |
| 18 |
| 512 |
| -9 |
| 9 |
| 0.5 |
The dot binds weaker than + and -: in 1 + 2 . 3 the
sum comes first and is then joined with the 3, and in 1 . 5 + 5 the 1 is joined
with 10. After a value a dot is the join, also right against it - 'a'.1 - and
only where no value stands before it does a dot start a number.
| HTML | RESULT |
|---|---|
| Order 42 |
| Total: 12 |
| 33 |
| 110 |
| 20 |
| a1 |
Each comparison has a word and a symbol: eq or == (a single
= too), ne, != or <>, and
lt le gt ge or < <= > >=. The words read better in a
template full of HTML. Numbers, and texts that are numbers, compare as numbers -
'2' lt '10' holds; other texts compare character by character, case counting.
PHP's === and !== are not there. A comparison answers
1 or nothing:
| HTML | RESULT |
|---|---|
| [1] [1] [] |
| [1] [1] [] |
| [1] [1] [1] |
| [] [1] |
| [1] [1] |
| [] [] |
and, or, xor and not, with
&&, || and ! as their symbols. The word
not binds weaker than the comparisons, so not $a eq $b denies the
comparison; ! binds as tightly as a sign, so !$a eq $b compares
!$a with $b. and and or stop at a left
side that decides: $n gt 0 and 10 / $n gt 1 never divides by zero.
| HTML | RESULT |
|---|---|
| [] [1] |
| [1] [] |
| [] [1] |
| [] [1] |
| [1] |
| [1] |
| [1] |
a ?? b answers a unless it is empty - '', NULL, FALSE,
an empty list - or a field that does not exist; then it answers b. A 0 is a value
and stays. A field in front of ?? may be missing, also under the strict check:
giving it a default is what the operator is for. The right side is worked out only when it
is wanted. In a pipe it takes the piped value, and the default function does
the same:
|
PHP fragments/expressions_18.php |
HTML fragments/expressions_18.pad |
Result |
|---|---|---|
|
|
no nickname 0 no surname nothing at all anonymous - anonymous |
cond ? then : else binds weakest of all: everything before the
? is the condition, and each branch runs to its : or to the end -
0 ? 'yes' : 'no' . '!' joins the '!' to the no. Only the branch
chosen is worked out. Ternaries in a row read from the right, a ? b : c ? d : e
being a ? b : (c ? d : e). The short form a ?: b answers
a itself when it holds, and with nothing before the ? the piped
value is the condition:
| HTML | RESULT |
|---|---|
| many |
| M |
| M |
| Untitled |
| Draft |
| none |
| no! |
|
PHP |
HTML fragments/expressions_20.pad |
Result |
|---|---|---|
|
1 pen 3 books 0 lamps - sold out |
Where a condition is wanted - {if}, where=, the
ternary, and and or - a value is tested as PHP tests it:
'', '0', 0, NULL, FALSE and an empty list are false, every other
value is true - the texts '0.0', 'false' and a space among
them.
| HTML | RESULT |
|---|---|
| false |
| false |
| false |
| false |
| false |
| true |
| true |
| true |
| true |
| true |
The comparisons, the tests and the logic operators answer 1 for true and
'' for false: written by {echo} a truth is a 1 or nothing at all, and truths
add up as numbers.
| HTML | RESULT |
|---|---|
| [1] [] |
| 2 |
| 1/ |
| holds |
| test | holds when |
|---|---|
$x in (a, b, ...) | the value equals one of the list |
$x like 'A%' | the value matches the SQL pattern: % any run of characters, _ one character, \\% and \\_ themselves; case is ignored |
$x matches '/re/' | the regular expression matches |
$x range (a, b) | a <= value <= b, the ends included |
$x between (a, b) | a < value < b, the ends left out |
$x contains y | the text holds y - or, for a list, an item of it equals y |
A not between the value and the test denies the test, as SQL writes it:
$s not in (...), not like, not matches,
not range. The value is everything left of the test - 5 + 1 in (6,
7) tests 6.
| HTML | RESULT |
|---|---|
| [1] [] |
| [1] |
| [1] |
| [1] |
| [] |
like ignores case; _ stands for exactly one character:
| HTML | RESULT |
|---|---|
| [1] [1] |
| [1] [] |
| [1] |
| [1] [] |
A backslash in a PAD string is an escape, so the backslash a regular expression needs is
written twice: '/a\\.b/'. A {n} quantifier would open a
tag - repeat the class, as below, or let the page's PHP hand the pattern over.
| HTML | RESULT |
|---|---|
| [1] |
| [1] [] |
| [1] [] |
| [1] |
| HTML | RESULT |
|---|---|
| [1] [1] [] |
| [] [1] |
| [1] |
| [1] |
contains looks into a text, or into a list for an item equal to the one asked
for:
| HTML | RESULT |
|---|---|
| [1] [] |
| [1] |
| [1] [] |
Each test is a pipe function too, so it can stand after a pipe or be called, its value the first argument:
| HTML | RESULT |
|---|---|
| [1] [1] |
| [1] [1] |
| [1] [1] |
| [1] |
Together with and and or they make the conditions of the
where option, which the data handling page
covers with the other options:
|
PHP |
HTML fragments/expressions_29.pad |
Result |
|---|---|---|
|
1: Ada, paid 4: Alice, sent |
The built-in pipe functions - upper, left, replace,
date and the rest of the {functions} list - are used two ways. After a pipe
they take the value on its left: $s | left(2). Written as a call with nothing
piped in they take it as their first argument: left($s, 2), as PHP's own
functions do - so they nest, and stand wherever a value can. The number of parameters is
checked.
| HTML | RESULT |
|---|---|
| ab |
| ab |
| Hello WORLD |
| ABC |
| a AND b |
| Dutch |
| HTML | RESULT |
|---|---|
| bcd |
| ef |
| example |
| creme-brulee-co |
| 1.5 KB |
| a long sentence… |
| 1.2M |
| 22nd |
php:name calls a PHP function, and so does a plain name followed by
( that is no PAD function - ucfirst('word'); the setting
$padPhpFunctions decides which PHP functions a template may call. A piped value
goes in as the only argument - 'abc' | php:strrev - and into a call with
arguments where @ stands: $n | php:number_format(@, 2).
| HTML | RESULT |
|---|---|
| 3 |
| ababab |
| cba |
| 1,234,567.89 |
| 1.234,50 |
| 007 |
| 9 3 |
| Word Word |
A file in the application's _functions/ directory is a pipe function as well,
the piped value its $value - this manual has _functions/stars.php.
function: asks for whatever function kind the name is, app: for the
application's own (see extending):
|
PHP |
HTML fragments/expressions_33.pad |
Result |
|---|---|---|
|
*** well done *** *** well done *** 17 |
A | hands the value on its left to what follows; the parts run left to right,
each over what the one before answered:
| HTML | RESULT |
|---|---|
| Ada Lovelace |
| EXAMPLE.COM |
| PAD!PAD! |
| 14.52 EUR |
A part after a pipe is an expression of its own, and the piped value fills the place of
the operand it lacks. An operator that opens the part takes it as its left side -
| + 1, | . ' EUR', | ?? 'none'. A space between such an
operator and its operand is required: | + 1, never | +1.
| HTML | RESULT |
|---|---|
| 6 |
| 9 |
| 25 |
| 1 |
| 256 |
| Hello world |
| HTML | RESULT |
|---|---|
| [1] |
| [1] |
| [1] |
| [1] |
| empty |
| 2 left |
@ stands for the piped value wherever the part needs it, as often as it
needs it:
| HTML | RESULT |
|---|---|
| 16 |
| 12 |
| "pad" |
| pad PAD |
| big |
A part that is a printf format - it starts with % and is one conversion -
formats the value as PHP's sprintf does. A % that is no format is
the remainder: | % 3.
| HTML | RESULT |
|---|---|
| 3.14 |
| 05.00 |
| 00042 |
| +42 |
| ff FF |
| 1.234500e+3 |
| 25.6% |
A pipe inside round or square brackets belongs to that group: ($n | + 1) * 2
adds before it multiplies, upper($s | trim) trims the argument, and in a list or
an argument list the pipe works on its own item. Outside brackets a pipe always ends the
whole expression before it.
| HTML | RESULT |
|---|---|
| 12 |
| PAD |
| 6 |
| 6-20 |
| xPADx |
A field tag with a pipe, {$x | upper}, writes its answer through
the sanitize chain, like every field tag. {echo} writes it raw - the right one for HTML
the page made itself, the wrong one for what a visitor typed:
|
PHP |
HTML fragments/expressions_40.pad |
Result |
|---|---|---|
|
<I>PAD</I> PAD |
date(format, modifier) reads a Unix timestamp, a date in text or a date object
the page's PHP made; the modifier is what PHP's strtotime reads, such as
'+1 week'. Written as a call it keeps PHP's order, the format first:
date('Y', $created). Dates written YYYY-MM-DD compare correctly as
plain text. now is the current time, and the
locale page has localDate:
| HTML | RESULT |
|---|---|
| 18 Oct 2026 |
| Sunday |
| 2026-10-25 |
| 14:30 |
| 2001 |
| [1] |
An arithmetic operator or a comparison that meets a list works with the sum of its
numbers. A list holding more than numbers, or met by the dot, is an error. A field that holds
a list is handed over with the array: prefix:
| HTML | RESULT |
|---|---|
| 7 |
| 10 |
| 6 |
| [1] |
| 3 |
| an empty list |
|
PHP |
HTML fragments/expressions_43.pad |
Result |
|---|---|---|
|
Sum 30, count 4 Average 7.5 Best 10, worst 4 7, 9, 4, 10 |
What is not a number - a NAN such as php:sqrt(-1) - is empty. %
works on whole numbers, as PHP's does; php:fmod keeps the fraction. Decimals are
written with PHP's precision, so 0.1 + 0.2 comes out as 0.3:
| HTML | RESULT |
|---|---|
| [] |
| not a number |
| 3 1 |
| 1 1.5 |
| 0.3 |
An expression's answer is a value, and a value never becomes template code: a field that
holds braces - from a database, a form, a file - is written as the text it is. To run it as
PAD on purpose, say so where it is used, with the code pipe (or
sandbox, which runs it in an isolated pass):
|
PHP fragments/expressions_45.php |
HTML fragments/expressions_45.pad |
Result |
|---|---|---|
|
|
{echo 6 * 7} {echo 6 * 7} is text 42 |
Under the strict syntax check - $padCheckSyntax, on by default - a mistake in
an expression is an error that names the fault and its place, and the page answers with the
error report instead of guessing. The report shows the template's file, line and column with
the lines around it (see errors in the template). What
some mistakes are told:
| written | the error says |
|---|---|
{echo (1 + 2} | the ( opened at position 1 is never closed |
{echo 'abc} | the string opened with ' at position 1 is never closed |
{echo $name | uppr} | there is no pipe function named 'uppr' |
{echo nofunc(1)} | there is no function named 'nofunc' |
{if $typo eq 1} | there is no field named '$typo' |
{echo $items + 1} | the field '$items' is a list, not a value |
{if $n eq} | the operator 'eq' has nothing on its right |
{echo $n + * 3} | the operators '+' and '*' stand side by side - a value is missing between them |
{if $n === 5} | '===' is no operator - eq (==) compares two values |
{echo $n | +1} | a pipe operator needs a space before its operand - write '| + 1', not '| +1' |
{echo 5 & 3} | '&' is no operator or value |
{if $n not 5} | a 'not' after a value denies a test - write $a not in (...), not like, not matches or not range, or put it in front: not $a eq $b |
{echo 7 / 0} | a division by zero in / |
{echo 'a' * 2} | 'a' is not a number for * |
{echo $n ? 'a'} | the ? of an inline ternary has no : - write cond ? then : else |
{echo [ 'a' => ]} | the key 'a' of a list has no value after its => |
{echo replace('abc')} | the function 'replace' wants 2 parameters after the value it works on - written as a call its first argument is that value: replace($value, ...) |
{echo php:str_repeat('x', -1)} | the PHP function 'str_repeat' refused its arguments: str_repeat(): Argument #2 ($times) must be greater than or equal to 0 |
{echo 'a\qb'} | Unsupported \ char |
With $padCheckSyntax = FALSE in _config/config.php nothing is
reported and the evaluator answers what it can: a text that is no number counts as 0
('a' + 1 is 1), a missing field is empty ($nope + 1 is 1), an
unknown escape loses its backslash, and an expression that cannot be worked out at all - a
bracket never closed, a division by zero, a PHP function refusing its arguments - answers
nothing. That suits old templates; a new one is better off with the check, which finds the
typo the lenient walk hides.
{if}, {case} and the ternary in templatesfirst@items and the others{!name}, {^name} and the rest$ and %