Inside PHP tags (see File structure) the compiler splits the bytes of the file into tokens. White space separates them and is otherwise ignored, except inside strings, and comments are skipped. A statement ends with a semicolon, or with a closing tag.
Tokens
The scanner produces named tokens such as T_VARIABLE,
T_STRING, T_LNUMBER and T_CONSTANT_ENCAPSED_STRING.
Parse errors name them, as in unexpected token "==". PHP code can read them
with the Tokenizer
extension (token_get_all(), and the PhpToken class added in
PHP 8.0). The full list is in the manual’s
List of parser tokens.
Since PHP 8.0 a namespaced name is one token: T_NAME_QUALIFIED for
App\Model, T_NAME_FULLY_QUALIFIED for \App\Model
and T_NAME_RELATIVE for namespace\Model. Spaces are no longer
allowed around the separators in a name, and keywords may be parts of a namespaced name.
White space is the space, tab and line break. It is required only where two tokens
would otherwise run together, such as echo $a.
Comments
| Form | Name | Ends at |
|---|---|---|
// text | One-line comment | The end of the line or a ?> tag, whichever is first |
# text | Shell-style one-line comment | The end of the line or a ?> tag |
/* text */ | Multi-line comment | The first */ |
/** text */ | Documentation comment (token T_DOC_COMMENT) | The first */ |
- Comments do not nest. A
/*inside a/* */comment has no meaning, and the first*/ends it. - Since PHP 8.0,
#[starts an attribute, so a#comment must not begin with[. - A documentation comment placed directly before a function, class, method or
property is kept by the engine and can be read with Reflection’s
getDocComment(). The language gives its contents no meaning. PHPDoc tags such as@paramare a convention read by tools.
Attribute syntax
An attribute group starts with the token #[ (T_ATTRIBUTE) and
ends with ]. It holds one or more attributes separated by commas, with an
optional trailing comma, and comes before the declaration it applies to.
attribute-group: #[ attribute {, attribute} [,] ]
attribute: name [ ( arguments ) ]
#[Route('/home', methods: ['GET'])]
#[Cache(60), Authorised]
function home(): string { return 'hello'; }
What attributes do, which declarations take them and how to read them is on the Attributes page.
Identifiers
Names of variables, functions, classes, constants, labels and so on follow one pattern, given in the manual as a regular expression:
^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$
- A name starts with a letter, an underscore or a byte from 128 to 255, then continues with those or digits. There is no length limit.
- Names are compared as bytes. UTF-8 names work because every byte of a multi-byte
UTF-8 character is in the allowed range. Two names that look the same but are
encoded differently, such as a precomposed
äandaplus a combining mark, are different names. - A variable name always starts with
$; the$is not part of the name. Other kinds of name have no sigil. - A variable name that does not fit the pattern can still exist if it is reached
dynamically:
${'invalid-name'} = 1;See Variable variables.
Case rules
Part of the language ignores case and part of it does not.
| Case-sensitive | Case-insensitive |
|---|---|
Variables and properties, constants (define() and const; the option to define a case-insensitive constant was deprecated in 7.3 and removed in 8.0), class constants and enum cases, array keys, goto labels |
Keywords and language constructs (IF, Echo), function and method names, class, interface, trait and enum names, namespace names, cast names such as (INT), magic constants, the values true, false and null |
Case-insensitive names are compared using ASCII rules. Autoloaders usually map class names to files, and file systems are often case-sensitive, so in practice a class should be used with the same case as its declaration.
Keywords
These words are reserved by the grammar. They cannot be used as the names of constants, functions or classes (manual: List of Keywords). Some look like functions but are language constructs: they need no parentheses in some cases, and cannot be called dynamically by name.
| Group | Keywords |
|---|---|
| Declarations and modifiers | abstract class const declare enddeclare extends final function fn global implements insteadof interface namespace new private protected public readonly static trait use var |
| Control flow | as break case catch continue default do else elseif endfor endforeach endif endswitch endwhile finally for foreach goto if match return switch throw try while yield yield from |
| Operators | and clone instanceof or xor |
| Output and inclusion | echo include include_once print require require_once |
| Language constructs written like calls | array() die() empty() eval() exit() isset() list() unset() __halt_compiler() |
| Type | callable |
In alphabetical order the full list is:
__halt_compiler abstract and array as break callable case catch class clone const
continue declare default die do echo else elseif empty enddeclare endfor endforeach
endif endswitch endwhile eval exit extends final finally fn for foreach function global
goto if implements include include_once instanceof insteadof interface isset list match
namespace new or print private protected public readonly require require_once return
static switch throw trait try unset use var while xor yield, plus yield
from, written as two words.
fn has been reserved since PHP 7.4, match since 8.0 and
readonly since 8.1; readonly may still be used as a function
name.
Keywords may be used as the names of properties, methods, class constants and enum
cases, except that class cannot name a class constant, because
Foo::class is the class-name fetch. They may also be named arguments.
Since PHP 7.0 this applies inside a class body. Elsewhere a keyword remains reserved.
Compile-time constants
__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__
__PROPERTY__ __TRAIT__. These are the
magic constants, replaced at
compile time.
Other reserved words
These may not name a class, interface, trait or enum, but are ordinary identifiers elsewhere. Before PHP 8.0 they were also forbidden in namespace names (manual).
| Word | Since |
|---|---|
self parent int float bool string true false null | Before 7.1 |
void iterable | 7.1 |
object | 7.2 |
mixed | 8.0 |
never | 8.1 |
array callable (as class names) | 8.5 |
The words enum, resource and numeric are soft
reserved: they still work as class names, but the manual warns against it. A class
named _ is deprecated since PHP 8.4. Note that enum at the
start of a declaration is treated as an
enum declaration only when followed by a name, so
code may still use enum as a function name.
Literals
| Kind | Examples | Type |
|---|---|---|
| Integer | 42 -7 0x1F 017 0o17 0b101 1_000_000 | int, or float if too large |
| Floating-point | 1.5 .5 1. 1e3 1E-3 1_234.5 | float |
| String | 'a' "a\n" <<<EOT <<<'EOT' | string |
| Boolean | true false | bool |
| Null | null | null |
| Array | [1, 2] ['a' => 1] array(1, 2) | array, see Arrays |
true, false and null are predefined constants that
are treated specially and work in any case. TRUE and
True are the same thing.
Integer literals
decimal: [1-9][0-9]*(_[0-9]+)* | 0
hexadecimal: 0[xX][0-9a-fA-F]+(_[0-9a-fA-F]+)*
octal: 0[oO]?[0-7]+(_[0-7]+)*
binary: 0[bB][01]+(_[01]+)*
| Base | Prefix | Example | Value | Since |
|---|---|---|---|---|
| Decimal | none, and no leading 0 | 255 | 255 | all versions |
| Hexadecimal | 0x or 0X | 0xFF | 255 | all versions |
| Octal | 0, or 0o or 0O | 0377 0o377 | 255 | 0o: 8.1 |
| Binary | 0b or 0B | 0b11111111 | 255 | 5.4 |
- A minus sign is the negation operator, not part of the literal.
- Underscores (PHP 7.4) may go between digits only:
1_000and0xFF_FFare valid,_1,1_and0x_FFare not. They are removed by the scanner and do not change the value. - A leading zero makes a literal octal:
010is 8. A digit 8 or 9 in an octal literal is a parse error. - A literal too large for
intbecomes afloat:9223372036854775808on a 64-bit platform is a float, soPHP_INT_MINcannot be written as a decimal literal. - There are no unsigned integers. The size and limits are in the constants
PHP_INT_SIZE,PHP_INT_MINandPHP_INT_MAX.
Floating-point literals
LNUM [0-9]+(_[0-9]+)*
DNUM ({LNUM}?"."{LNUM}) | ({LNUM}"."{LNUM}?)
EXPONENT_DNUM (({LNUM} | {DNUM}) [eE][+-]? {LNUM})
- A float literal needs a decimal point, an exponent or both:
1.5,1.,.5,1e3. - Underscores are allowed between digits from PHP 7.4:
1_234.567_89. - Floats are stored as IEEE 754 double precision on normal builds. There are no
literals for infinity or NaN; use the constants
INFandNAN.
Strings
A PHP string is a sequence of bytes. There is no character encoding attached to it,
so a string literal holds whatever bytes the source file holds. Multi-byte text
functions live in the mbstring and intl extensions. There are
four ways to write one.
| Form | Escapes | Interpolation |
|---|---|---|
Single-quoted '…' | Only \' and \\ | No |
Double-quoted "…" | Yes, all | Yes |
Heredoc <<<NAME | Yes, all (a " needs no escape) | Yes |
Nowdoc <<<'NAME' | No | No |
Single-quoted strings
Only two sequences mean anything: \' is a single quote and
\\ is a backslash. Every other backslash is literal, so
'\n' is two bytes, a backslash and an n. Variables are not
expanded. The string may span lines.
Double-quoted strings
| Escape | Meaning |
|---|---|
\n | Line feed (0x0A) |
\r | Carriage return (0x0D) |
\t | Horizontal tab (0x09) |
\v | Vertical tab (0x0B) |
\e | Escape (0x1B) |
\f | Form feed (0x0C) |
\\ | Backslash |
\$ | Dollar sign, not starting a variable |
\" | Double quote |
\[0-7]{1,3} | A byte in octal. Values overflow silently: "\400" is the same as "\000" |
\x[0-9A-Fa-f]{1,2} | A byte in hexadecimal |
\u{[0-9A-Fa-f]+} | A Unicode code point written as UTF-8 bytes (PHP 7.0). The braces are required |
Any other backslash is kept: "\q" is two bytes. Single quotes need no
escaping in a double-quoted string.
Heredoc
A heredoc starts with <<<, an identifier and a line break, and
ends at a closing identifier. It works like a double-quoted string, and double
quotes inside it need no escape. The identifier may be written in double quotes:
<<<"NAME".
$name = 'Ada';
$text = <<<EOT
Hello, {$name}.
The "quotes" need no escape.
EOT;
// "Hello, Ada.\n The \"quotes\" need no escape."
Since PHP 7.3:
- The closing identifier may be indented with spaces or tabs. That indentation is removed from the start of every line of the body.
- Every body line must be indented at least as far as the closing identifier, or
a
ParseErroris thrown. Blank lines are exempt. - Spaces and tabs must not be mixed in the indentation of the body and the closing identifier.
- The closing identifier can be followed by more code on the same line, so a heredoc can be an array element or an argument.
- A body line that starts with the closing identifier ends the heredoc, even as part of a longer word. Do not use a word from the text as the identifier.
Before 7.3 the closing identifier had to start in the first column and stand alone on its line, with at most a semicolon after it.
Nowdoc
A nowdoc (PHP 5.3) is a heredoc whose opening identifier is in single quotes:
<<<'NAME'. Nothing inside it is processed: no escapes, no
interpolation, and backslashes are literal. The closing identifier follows the same
rules as a heredoc.
Interpolation
Double-quoted strings and heredocs replace variables with their values. The manual describes two forms, plus a third that is deprecated.
Simple form
A $ followed by a valid name starts a variable. After the name, one of
these may follow:
[name],[$var]or[integer]: an array element. A key is written without quotes, so it is a string key, and a constant cannot be used. Negative integer offsets have worked since PHP 7.1.->name: one property. Only one level is read, so"$a->b->c"reads$a->band adds the text->c.
If no valid name follows, the $ is literal.
$fruit = ['apple', 'name' => 'pear'];
echo "I ate $fruit[0] and $fruit[name]."; // I ate apple and pear.
$p = new stdClass;
$p->x = 3;
echo "x is $p->x"; // x is 3
Complex form
{$expr} allows any expression that starts with a variable and is
reachable by property, array and method access. The { must be directly
followed by the $; { $x} is literal text. Use
{\$ to get a literal {$.
echo "{$arr['key']}"; // quoted keys need this form
echo "{$arr[3][2]}";
echo "{$obj->values[3]->name}";
echo "{$square->width}00 cm"; // the braces end the name before the zeros
echo "{${$name}}"; // a variable variable
The deprecated ${…} forms
"${var}" and "${expr}" were deprecated in PHP 8.2. Use
"{$var}" and "{${expr}}" instead.
Punctuation
| Token | Used for |
|---|---|
$ | Variable sigil |
; | Ends a statement |
, | Separates list items |
( ) | Grouping, calls, parameter lists, casts |
[ ] | Array literals, element access, destructuring |
{ } | Blocks and class bodies |
-> ?-> | Object member access, and the nullsafe form (PHP 8.0) |
:: | Static member access (the token is T_DOUBLE_COLON; its other name is T_PAAMAYIM_NEKUDOTAYIM) |
=> | Array keys, match arms, arrow functions |
... | Variadics, argument unpacking and first-class callables |
\ | Namespace separator |
#[ | Starts an attribute group |
All operators, with their precedence, are listed on the Expressions page.